@@ -4,7 +4,8 @@ import "sync/atomic"
44
55type (
66 Atom struct {
7- state atomic.Value
7+ state atomic.Value
8+ watches IPersistentMap
89
910 meta IPersistentMap
1011 }
1819func NewAtom(val any) *Atom {
1920 a := &Atom{}
2021 a.state.Store(Box{val})
22+ a.watches = emptyMap
2123 return a
2224}
2325
@@ -33,11 +35,35 @@ func (a *Atom) Deref() interface{} {
3335 return a.state.Load().(Box).val
3436}
3537
36- func (a *Atom) SetValidator(vf IFn) { panic("not implemented") }
37- func (a *Atom) Validator() IFn { panic("not implemented") }
38- func (a *Atom) Watches() IPersistentMap { panic("not implemented") }
39- func (a *Atom) AddWatch(key interface{}, fn IFn) { panic("not implemented") }
40- func (a *Atom) RemoveWatch(key interface{}) { panic("not implemented") }
38+ func (a *Atom) SetValidator(vf IFn) { panic("not implemented") }
39+ func (a *Atom) Validator() IFn { panic("not implemented") }
40+ func (a *Atom) Watches() IPersistentMap {
41+ return a.watches
42+ }
43+
44+ func (a *Atom) AddWatch(key interface{}, fn IFn) IRef {
45+ a.watches = a.watches.Assoc(key, fn).(IPersistentMap)
46+ return a
47+ }
48+
49+ func (a *Atom) RemoveWatch(key interface{}) {
50+ a.watches = a.watches.Without(key)
51+ }
52+
53+ func (a *Atom) notifyWatches(oldVal, newVal interface{}) {
54+ watches := a.watches
55+ if watches == nil || watches.Count() == 0 {
56+ return
57+ }
58+
59+ for seq := watches.Seq(); seq != nil; seq = seq.Next() {
60+ entry := seq.First().(IMapEntry)
61+ key := entry.Key()
62+ fn := entry.Val().(IFn)
63+ // Call watch function with key, ref, old-state, new-state
64+ fn.Invoke(key, a, oldVal, newVal)
65+ }
66+ }
4167
4268func (a *Atom) Swap(f IFn, args ISeq) interface{} {
4369 for {
@@ -51,16 +77,19 @@ func (a *Atom) Swap(f IFn, args ISeq) interface{} {
5177
5278func (a *Atom) CompareAndSet(oldv, newv interface{}) bool {
5379 // TODO: validate
54- // TODO: notifyWatches
55- return a.state.CompareAndSwap(Box{val: oldv}, Box{val: newv})
80+ swapped := a.state.CompareAndSwap(Box{val: oldv}, Box{val: newv})
81+ if swapped {
82+ a.notifyWatches(oldv, newv)
83+ }
84+ return swapped
5685}
5786
5887func (a *Atom) Reset(newVal interface{}) interface{} {
59- // old := a.state.Load().(Box)
88+ old := a.state.Load().(Box)
6089 // TODO: validate
6190
6291 a.state.Store(Box{newVal})
63- // TODO: notifyWatches
92+ a. notifyWatches(old.val, newVal)
6493 return newVal
6594}
6695
0 commit comments