11package lang
22
3- import "sync/atomic"
3+ import (
4+ "sync"
5+ "sync/atomic"
6+ )
47
58type (
69 Atom struct {
710 state atomic.Pointer [Box ]
811 initial Box
9- watches IPersistentMap
1012
11- meta IPersistentMap
13+ referenceMu sync.RWMutex
14+ watches IPersistentMap
15+ validator IFn
16+ meta IPersistentMap
1217 }
1318)
1419
@@ -36,23 +41,49 @@ func (a *Atom) Deref() interface{} {
3641 return a .state .Load ().val
3742}
3843
39- func (a * Atom ) SetValidator (vf IFn ) { panic ("not implemented" ) }
40- func (a * Atom ) Validator () IFn { panic ("not implemented" ) }
44+ func (a * Atom ) SetValidator (vf IFn ) {
45+ if vf != nil && ! IsTruthy (Apply1 (vf , a .Deref ())) {
46+ panic (NewIllegalStateError ("Invalid reference state" ))
47+ }
48+ a .referenceMu .Lock ()
49+ a .validator = vf
50+ a .referenceMu .Unlock ()
51+ }
52+
53+ func (a * Atom ) Validator () IFn {
54+ a .referenceMu .RLock ()
55+ defer a .referenceMu .RUnlock ()
56+ return a .validator
57+ }
58+
59+ // GetValidator is the JVM-style IRef alias used by Clojure host interop.
60+ func (a * Atom ) GetValidator () IFn {
61+ return a .Validator ()
62+ }
63+
4164func (a * Atom ) Watches () IPersistentMap {
65+ a .referenceMu .RLock ()
66+ defer a .referenceMu .RUnlock ()
4267 return a .watches
4368}
4469
4570func (a * Atom ) AddWatch (key interface {}, fn IFn ) IRef {
71+ a .referenceMu .Lock ()
72+ defer a .referenceMu .Unlock ()
4673 a .watches = a .watches .Assoc (key , fn ).(IPersistentMap )
4774 return a
4875}
4976
5077func (a * Atom ) RemoveWatch (key interface {}) {
78+ a .referenceMu .Lock ()
79+ defer a .referenceMu .Unlock ()
5180 a .watches = a .watches .Without (key )
5281}
5382
5483func (a * Atom ) notifyWatches (oldVal , newVal interface {}) {
84+ a .referenceMu .RLock ()
5585 watches := a .watches
86+ a .referenceMu .RUnlock ()
5687 if watches == nil || watches .Count () == 0 {
5788 return
5889 }
@@ -66,10 +97,26 @@ func (a *Atom) notifyWatches(oldVal, newVal interface{}) {
6697 }
6798}
6899
100+ func (a * Atom ) validate (newVal interface {}) {
101+ a .referenceMu .RLock ()
102+ validator := a .validator
103+ a .referenceMu .RUnlock ()
104+ if validator != nil && ! IsTruthy (Apply1 (validator , newVal )) {
105+ panic (NewIllegalStateError ("Invalid reference state" ))
106+ }
107+ }
108+
109+ func (a * Atom ) hasWatches () bool {
110+ a .referenceMu .RLock ()
111+ defer a .referenceMu .RUnlock ()
112+ return a .watches != nil && a .watches .Count () != 0
113+ }
114+
69115func (a * Atom ) Swap (f IFn , args ISeq ) interface {} {
70116 for {
71117 old := a .state .Load ()
72118 nw := f .ApplyTo (NewCons (old .val , args ))
119+ a .validate (nw )
73120 if a .compareAndSetBox (old , nw ) {
74121 return nw
75122 }
@@ -83,6 +130,7 @@ func (a *Atom) Swap0(f IFn) interface{} {
83130 for {
84131 old := a .state .Load ()
85132 nw := Apply1 (f , old .val )
133+ a .validate (nw )
86134 if a .compareAndSetBox (old , nw ) {
87135 return nw
88136 }
@@ -93,6 +141,7 @@ func (a *Atom) Swap1(f IFn, x interface{}) interface{} {
93141 for {
94142 old := a .state .Load ()
95143 nw := Apply2 (f , old .val , x )
144+ a .validate (nw )
96145 if a .compareAndSetBox (old , nw ) {
97146 return nw
98147 }
@@ -103,6 +152,7 @@ func (a *Atom) Swap2(f IFn, x, y interface{}) interface{} {
103152 for {
104153 old := a .state .Load ()
105154 nw := Apply3 (f , old .val , x , y )
155+ a .validate (nw )
106156 if a .compareAndSetBox (old , nw ) {
107157 return nw
108158 }
@@ -114,13 +164,13 @@ func (a *Atom) CompareAndSet(oldv, newv interface{}) bool {
114164 if ! Identical (old .val , oldv ) {
115165 return false
116166 }
167+ a .validate (newv )
117168 return a .compareAndSetBox (old , newv )
118169}
119170
120171func (a * Atom ) compareAndSetBox (old * Box , newv interface {}) bool {
121- // TODO: validate
122172 if Identical (old .val , newv ) &&
123- ( a . watches == nil || a . watches . Count () == 0 ) {
173+ ! a . hasWatches ( ) {
124174 return a .state .CompareAndSwap (old , old )
125175 }
126176 swapped := a .state .CompareAndSwap (old , NewBox (newv ))
@@ -131,11 +181,11 @@ func (a *Atom) compareAndSetBox(old *Box, newv interface{}) bool {
131181}
132182
133183func (a * Atom ) Reset (newVal interface {}) interface {} {
134- // TODO: validate
184+ a . validate ( newVal )
135185 for {
136186 old := a .state .Load ()
137187 if Identical (old .val , newVal ) &&
138- ( a . watches == nil || a . watches . Count () == 0 ) {
188+ ! a . hasWatches ( ) {
139189 if a .state .CompareAndSwap (old , old ) {
140190 return newVal
141191 }
@@ -148,8 +198,19 @@ func (a *Atom) Reset(newVal interface{}) interface{} {
148198}
149199
150200func (a * Atom ) Meta () IPersistentMap {
151- if a .meta == nil {
152- return nil
153- }
201+ a .referenceMu .RLock ()
202+ defer a .referenceMu .RUnlock ()
154203 return a .meta
155204}
205+
206+ func (a * Atom ) AlterMeta (f IFn , args ISeq ) IPersistentMap {
207+ meta := ApplySeq (f , NewCons (a .Meta (), args )).(IPersistentMap )
208+ return a .ResetMeta (meta )
209+ }
210+
211+ func (a * Atom ) ResetMeta (meta IPersistentMap ) IPersistentMap {
212+ a .referenceMu .Lock ()
213+ a .meta = meta
214+ a .referenceMu .Unlock ()
215+ return meta
216+ }
0 commit comments