value.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package opt
  4. import (
  5. "fmt"
  6. "reflect"
  7. jsonv2 "github.com/go-json-experiment/json"
  8. "github.com/go-json-experiment/json/jsontext"
  9. )
  10. // Value is an optional value to be JSON-encoded.
  11. // With [encoding/json], a zero Value is marshaled as a JSON null.
  12. // With [github.com/go-json-experiment/json], a zero Value is omitted from the
  13. // JSON object if the Go struct field specified with omitzero.
  14. // The omitempty tag option should never be used with Value fields.
  15. type Value[T any] struct {
  16. value T
  17. set bool
  18. }
  19. // Equal reports whether the receiver and the other value are equal.
  20. // If the template type T in Value[T] implements an Equal method, it will be used
  21. // instead of the == operator for comparing values.
  22. type equatable[T any] interface {
  23. // Equal reports whether the receiver and the other values are equal.
  24. Equal(other T) bool
  25. }
  26. // ValueOf returns an optional Value containing the specified value.
  27. // It treats nil slices and maps as empty slices and maps.
  28. func ValueOf[T any](v T) Value[T] {
  29. return Value[T]{value: v, set: true}
  30. }
  31. // String implements [fmt.Stringer].
  32. func (o Value[T]) String() string {
  33. if !o.set {
  34. return fmt.Sprintf("(empty[%T])", o.value)
  35. }
  36. return fmt.Sprint(o.value)
  37. }
  38. // Set assigns the specified value to the optional value o.
  39. func (o *Value[T]) Set(v T) {
  40. *o = ValueOf(v)
  41. }
  42. // Clear resets o to an empty state.
  43. func (o *Value[T]) Clear() {
  44. *o = Value[T]{}
  45. }
  46. // IsSet reports whether o has a value set.
  47. func (o *Value[T]) IsSet() bool {
  48. return o.set
  49. }
  50. // Get returns the value of o.
  51. // If a value hasn't been set, a zero value of T will be returned.
  52. func (o Value[T]) Get() T {
  53. return o.value
  54. }
  55. // GetOr returns the value of o or def if a value hasn't been set.
  56. func (o Value[T]) GetOr(def T) T {
  57. if o.set {
  58. return o.value
  59. }
  60. return def
  61. }
  62. // Get returns the value and a flag indicating whether the value is set.
  63. func (o Value[T]) GetOk() (v T, ok bool) {
  64. return o.value, o.set
  65. }
  66. // Equal reports whether o is equal to v.
  67. // Two optional values are equal if both are empty,
  68. // or if both are set and the underlying values are equal.
  69. // If the template type T implements an Equal(T) bool method, it will be used
  70. // instead of the == operator for value comparison.
  71. // If T is not comparable, it returns false.
  72. func (o Value[T]) Equal(v Value[T]) bool {
  73. if o.set != v.set {
  74. return false
  75. }
  76. if !o.set {
  77. return true
  78. }
  79. ov := any(o.value)
  80. if eq, ok := ov.(equatable[T]); ok {
  81. return eq.Equal(v.value)
  82. }
  83. if reflect.TypeFor[T]().Comparable() {
  84. return ov == any(v.value)
  85. }
  86. return false
  87. }
  88. // MarshalJSONTo implements [jsonv2.MarshalerTo].
  89. func (o Value[T]) MarshalJSONTo(enc *jsontext.Encoder) error {
  90. if !o.set {
  91. return enc.WriteToken(jsontext.Null)
  92. }
  93. return jsonv2.MarshalEncode(enc, &o.value)
  94. }
  95. // UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom].
  96. func (o *Value[T]) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
  97. if dec.PeekKind() == 'n' {
  98. *o = Value[T]{}
  99. _, err := dec.ReadToken() // read null
  100. return err
  101. }
  102. o.set = true
  103. return jsonv2.UnmarshalDecode(dec, &o.value)
  104. }
  105. // MarshalJSON implements [json.Marshaler].
  106. func (o Value[T]) MarshalJSON() ([]byte, error) {
  107. return jsonv2.Marshal(o) // uses MarshalJSONTo
  108. }
  109. // UnmarshalJSON implements [json.Unmarshaler].
  110. func (o *Value[T]) UnmarshalJSON(b []byte) error {
  111. return jsonv2.Unmarshal(b, o) // uses UnmarshalJSONFrom
  112. }