66
77 "github.com/iotaledger/hive.go/core/generics/constraints"
88 "github.com/iotaledger/hive.go/core/generics/lo"
9+ "github.com/iotaledger/hive.go/core/generics/options"
910)
1011
1112// Item represents an item in the OnChangeMap.
@@ -14,53 +15,105 @@ type Item[K comparable, C constraints.ComparableStringer[K]] interface {
1415 Clone () Item [K , C ]
1516}
1617
17- // OnChangeMap is a map that executes a callback if the map or an item is modified,
18+ // OnChangeMap is a map that executes callbacks if the map or an item is modified,
1819// in case callbackEnabled is true.
1920type OnChangeMap [K comparable , C constraints.ComparableStringer [K ], I Item [K , C ]] struct {
2021 mutex sync.RWMutex
2122
22- m map [K ]I
23- callback func ([]I ) error
24- callbackEnabled bool
23+ m map [K ]I
24+ callbacksEnabled bool
25+
26+ changedCallback func ([]I ) error
27+ itemAddedCallback func (I ) error
28+ itemModifiedCallback func (I ) error
29+ itemDeletedCallback func (I ) error
2530}
2631
27- // NewOnChangeMap creates a new OnChangeMap.
28- func NewOnChangeMap [K comparable , C constraints.ComparableStringer [K ], I Item [K , C ]](callback func ([]I ) error ) * OnChangeMap [K , C , I ] {
29- return & OnChangeMap [K , C , I ]{
30- m : make (map [K ]I ),
31- callback : callback ,
32- callbackEnabled : false ,
32+ // WithChangedCallback is triggered when something in the OnChangeMap is changed (added/modified/deleted).
33+ func WithChangedCallback [K comparable , C constraints.ComparableStringer [K ], I Item [K , C ]](changedCallback func ([]I ) error ) options.Option [OnChangeMap [K , C , I ]] {
34+ return func (r * OnChangeMap [K , C , I ]) {
35+ r .changedCallback = changedCallback
36+ }
37+ }
38+
39+ // WithItemAddedCallback is triggered when a new item is added.
40+ func WithItemAddedCallback [K comparable , C constraints.ComparableStringer [K ], I Item [K , C ]](itemAddedCallback func (I ) error ) options.Option [OnChangeMap [K , C , I ]] {
41+ return func (r * OnChangeMap [K , C , I ]) {
42+ r .itemAddedCallback = itemAddedCallback
43+ }
44+ }
45+
46+ // WithItemModifiedCallback is triggered when an item is modified.
47+ func WithItemModifiedCallback [K comparable , C constraints.ComparableStringer [K ], I Item [K , C ]](itemModifiedCallback func (I ) error ) options.Option [OnChangeMap [K , C , I ]] {
48+ return func (r * OnChangeMap [K , C , I ]) {
49+ r .itemModifiedCallback = itemModifiedCallback
50+ }
51+ }
52+
53+ // WithItemDeletedCallback is triggered when an item is deleted.
54+ func WithItemDeletedCallback [K comparable , C constraints.ComparableStringer [K ], I Item [K , C ]](itemDeletedCallback func (I ) error ) options.Option [OnChangeMap [K , C , I ]] {
55+ return func (r * OnChangeMap [K , C , I ]) {
56+ r .itemDeletedCallback = itemDeletedCallback
3357 }
3458}
3559
36- // CallbackEnabled sets whether executing the callback on change is active or not.
37- func (r * OnChangeMap [K , C , I ]) CallbackEnabled (enabled bool ) {
38- r .callbackEnabled = enabled
60+ // NewOnChangeMap creates a new OnChangeMap.
61+ func NewOnChangeMap [K comparable , C constraints.ComparableStringer [K ], I Item [K , C ]](opts ... options.Option [OnChangeMap [K , C , I ]]) * OnChangeMap [K , C , I ] {
62+ return options .Apply (& OnChangeMap [K , C , I ]{
63+ m : make (map [K ]I ),
64+ callbacksEnabled : false ,
65+ changedCallback : nil ,
66+ itemAddedCallback : nil ,
67+ itemModifiedCallback : nil ,
68+ itemDeletedCallback : nil ,
69+ }, opts )
70+ }
71+
72+ // CallbacksEnabled sets whether executing the callbacks on change is active or not.
73+ func (r * OnChangeMap [K , C , I ]) CallbacksEnabled (enabled bool ) {
74+ r .callbacksEnabled = enabled
3975}
4076
41- // executeCallbackWithoutLocking calls the callback if callbackEnabled is true.
42- func (r * OnChangeMap [K , C , I ]) executeCallbackWithoutLocking () error {
43- if ! r .callbackEnabled {
77+ // executeChangedCallback calls the changedCallback if callbackEnabled is true.
78+ func (r * OnChangeMap [K , C , I ]) executeChangedCallback () error {
79+ if ! r .callbacksEnabled {
4480 return nil
4581 }
4682
47- if r .callback == nil {
83+ if r .changedCallback != nil {
84+ if err := r .changedCallback (lo .Values (r .m )); err != nil {
85+ return fmt .Errorf ("failed to execute callback in OnChangeMap: %w" , err )
86+ }
87+ }
88+
89+ return nil
90+ }
91+
92+ // executeItemCallback calls the given callback if callbackEnabled is true.
93+ func (r * OnChangeMap [K , C , I ]) executeItemCallback (callback func (I ) error , item I ) error {
94+ if ! r .callbacksEnabled {
4895 return nil
4996 }
5097
51- if err := r .callback (lo .Values (r .m )); err != nil {
52- return fmt .Errorf ("failed to execute callback in OnChangeMap: %w" , err )
98+ if err := r .executeChangedCallback (); err != nil {
99+ return err
100+ }
101+
102+ if callback != nil {
103+ if err := callback (item ); err != nil {
104+ return fmt .Errorf ("failed to execute item callback in OnChangeMap: %w" , err )
105+ }
53106 }
54107
55108 return nil
56109}
57110
58- // ExecuteCallback calls the callback if callbackEnabled is true.
59- func (r * OnChangeMap [K , C , I ]) ExecuteCallback () error {
111+ // ExecuteChangedCallback calls the changedCallback if callbackEnabled is true.
112+ func (r * OnChangeMap [K , C , I ]) ExecuteChangedCallback () error {
60113 r .mutex .RLock ()
61114 defer r .mutex .RUnlock ()
62115
63- return r .executeCallbackWithoutLocking ()
116+ return r .executeChangedCallback ()
64117}
65118
66119// All returns a copy of all items.
@@ -100,7 +153,7 @@ func (r *OnChangeMap[K, C, I]) Add(item I) error {
100153
101154 r .m [item .ID ().Key ()] = item
102155
103- return r .executeCallbackWithoutLocking ( )
156+ return r .executeItemCallback ( r . itemAddedCallback , item )
104157}
105158
106159// Modify modifies an item in the map and returns a copy.
@@ -118,19 +171,20 @@ func (r *OnChangeMap[K, C, I]) Modify(id C, callback func(item I) bool) (I, erro
118171 return item .Clone ().(I ), nil
119172 }
120173
121- return item .Clone ().(I ), r .executeCallbackWithoutLocking ( )
174+ return item .Clone ().(I ), r .executeItemCallback ( r . itemModifiedCallback , item )
122175}
123176
124177// Delete removes an item from the map.
125178func (r * OnChangeMap [K , C , I ]) Delete (id C ) error {
126179 r .mutex .Lock ()
127180 defer r .mutex .Unlock ()
128181
129- if _ , exists := r .m [id .Key ()]; ! exists {
182+ item , exists := r .m [id .Key ()]
183+ if ! exists {
130184 return fmt .Errorf ("unable to remove item: \" %s\" does not exist in map" , id )
131185 }
132186
133187 delete (r .m , id .Key ())
134188
135- return r .executeCallbackWithoutLocking ( )
189+ return r .executeItemCallback ( r . itemDeletedCallback , item )
136190}
0 commit comments