@ -23,11 +23,18 @@ func initClosedChan() <-chan struct{} {
return ch
}
// AtomicValue is the generic version of atomic.Value.
// AtomicValue is the generic version of [ atomic.Value] .
type AtomicValue [ T any ] struct {
v atomic . Value
}
// wrappedValue is used to wrap a value T in a concrete type,
// otherwise atomic.Value.Store may panic due to mismatching types in interfaces.
// This wrapping is not necessary for non-interface kinds of T,
// but there is no harm in wrapping anyways.
// See https://cs.opensource.google/go/go/+/refs/tags/go1.22.2:src/sync/atomic/value.go;l=78
type wrappedValue [ T any ] struct { v T }
// Load returns the value set by the most recent Store.
// It returns the zero value for T if the value is empty.
func ( v * AtomicValue [ T ] ) Load ( ) T {
@ -40,7 +47,7 @@ func (v *AtomicValue[T]) Load() T {
func ( v * AtomicValue [ T ] ) LoadOk ( ) ( _ T , ok bool ) {
x := v . v . Load ( )
if x != nil {
return x . ( T) , true
return x . ( wrappedValue[ T] ) . v , true
}
var zero T
return zero , false
@ -48,22 +55,22 @@ func (v *AtomicValue[T]) LoadOk() (_ T, ok bool) {
// Store sets the value of the Value to x.
func ( v * AtomicValue [ T ] ) Store ( x T ) {
v . v . Store ( x)
v . v . Store ( wrappedValue[ T ] { x} )
}
// Swap stores new into Value and returns the previous value.
// It returns the zero value for T if the value is empty.
func ( v * AtomicValue [ T ] ) Swap ( x T ) ( old T ) {
oldV := v . v . Swap ( x)
oldV := v . v . Swap ( wrappedValue[ T ] { x} )
if oldV != nil {
return oldV . ( T)
return oldV . ( wrappedValue[ T] ) . v
}
return old
}
// CompareAndSwap executes the compare-and-swap operation for the Value.
func ( v * AtomicValue [ T ] ) CompareAndSwap ( oldV , newV T ) ( swapped bool ) {
return v . v . CompareAndSwap ( oldV, newV)
return v . v . CompareAndSwap ( wrappedValue[ T ] { oldV} , wrappedValue[ T ] { newV} )
}
// WaitGroupChan is like a sync.WaitGroup, but has a chan that closes