value.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. package atomic
  2. import (
  3. "encoding/json"
  4. "sync/atomic"
  5. )
  6. func DefaultValue[T any]() T {
  7. var defaultValue T
  8. return defaultValue
  9. }
  10. type TypedValue[T any] struct {
  11. _ noCopy
  12. value atomic.Value
  13. }
  14. // tValue is a struct with determined type to resolve atomic.Value usages with interface types
  15. // https://github.com/golang/go/issues/22550
  16. //
  17. // The intention to have an atomic value store for errors. However, running this code panics:
  18. // panic: sync/atomic: store of inconsistently typed value into Value
  19. // This is because atomic.Value requires that the underlying concrete type be the same (which is a reasonable expectation for its implementation).
  20. // When going through the atomic.Value.Store method call, the fact that both these are of the error interface is lost.
  21. type tValue[T any] struct {
  22. value T
  23. }
  24. func (t *TypedValue[T]) Load() T {
  25. value := t.value.Load()
  26. if value == nil {
  27. return DefaultValue[T]()
  28. }
  29. return value.(tValue[T]).value
  30. }
  31. func (t *TypedValue[T]) Store(value T) {
  32. t.value.Store(tValue[T]{value})
  33. }
  34. func (t *TypedValue[T]) Swap(new T) T {
  35. old := t.value.Swap(tValue[T]{new})
  36. if old == nil {
  37. return DefaultValue[T]()
  38. }
  39. return old.(tValue[T]).value
  40. }
  41. func (t *TypedValue[T]) CompareAndSwap(old, new T) bool {
  42. return t.value.CompareAndSwap(tValue[T]{old}, tValue[T]{new})
  43. }
  44. func (t *TypedValue[T]) MarshalJSON() ([]byte, error) {
  45. return json.Marshal(t.Load())
  46. }
  47. func (t *TypedValue[T]) UnmarshalJSON(b []byte) error {
  48. var v T
  49. if err := json.Unmarshal(b, &v); err != nil {
  50. return err
  51. }
  52. t.Store(v)
  53. return nil
  54. }
  55. func NewTypedValue[T any](t T) (v TypedValue[T]) {
  56. v.Store(t)
  57. return
  58. }
  59. type noCopy struct{}
  60. // Lock is a no-op used by -copylocks checker from `go vet`.
  61. func (*noCopy) Lock() {}
  62. func (*noCopy) Unlock() {}