map.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // Copyright (c) Tailscale Inc & AUTHORS
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. package prefs
  4. import (
  5. "maps"
  6. "net/netip"
  7. jsonv2 "github.com/go-json-experiment/json"
  8. "github.com/go-json-experiment/json/jsontext"
  9. "golang.org/x/exp/constraints"
  10. "tailscale.com/types/opt"
  11. "tailscale.com/types/ptr"
  12. "tailscale.com/types/views"
  13. )
  14. // MapKeyType is a constraint allowing types that can be used as [Map] and [StructMap] keys.
  15. // To satisfy this requirement, a type must be comparable and must encode as a JSON string.
  16. // See [jsonv2.Marshal] for more details.
  17. type MapKeyType interface {
  18. ~string | constraints.Integer | netip.Addr | netip.Prefix | netip.AddrPort
  19. }
  20. // Map is a preference type that holds immutable key-value pairs.
  21. type Map[K MapKeyType, V ImmutableType] struct {
  22. preference[map[K]V]
  23. }
  24. // MapOf returns a map configured with the specified value and [Options].
  25. func MapOf[K MapKeyType, V ImmutableType](v map[K]V, opts ...Options) Map[K, V] {
  26. return Map[K, V]{preferenceOf(opt.ValueOf(v), opts...)}
  27. }
  28. // MapWithOpts returns an unconfigured [Map] with the specified [Options].
  29. func MapWithOpts[K MapKeyType, V ImmutableType](opts ...Options) Map[K, V] {
  30. return Map[K, V]{preferenceOf(opt.Value[map[K]V]{}, opts...)}
  31. }
  32. // View returns a read-only view of m.
  33. func (m *Map[K, V]) View() MapView[K, V] {
  34. return MapView[K, V]{m}
  35. }
  36. // Clone returns a copy of m that aliases no memory with m.
  37. func (m Map[K, V]) Clone() *Map[K, V] {
  38. res := ptr.To(m)
  39. if v, ok := m.s.Value.GetOk(); ok {
  40. res.s.Value.Set(maps.Clone(v))
  41. }
  42. return res
  43. }
  44. // Equal reports whether m and m2 are equal.
  45. func (m Map[K, V]) Equal(m2 Map[K, V]) bool {
  46. if m.s.Metadata != m2.s.Metadata {
  47. return false
  48. }
  49. v1, ok1 := m.s.Value.GetOk()
  50. v2, ok2 := m2.s.Value.GetOk()
  51. if ok1 != ok2 {
  52. return false
  53. }
  54. return !ok1 || maps.Equal(v1, v2)
  55. }
  56. // MapView is a read-only view of a [Map].
  57. type MapView[K MapKeyType, V ImmutableType] struct {
  58. // ж is the underlying mutable value, named with a hard-to-type
  59. // character that looks pointy like a pointer.
  60. // It is named distinctively to make you think of how dangerous it is to escape
  61. // to callers. You must not let callers be able to mutate it.
  62. ж *Map[K, V]
  63. }
  64. // Valid reports whether the underlying [Map] is non-nil.
  65. func (mv MapView[K, V]) Valid() bool {
  66. return mv.ж != nil
  67. }
  68. // AsStruct implements [views.StructView] by returning a clone of the [Map]
  69. // which aliases no memory with the original.
  70. func (mv MapView[K, V]) AsStruct() *Map[K, V] {
  71. if mv.ж == nil {
  72. return nil
  73. }
  74. return mv.ж.Clone()
  75. }
  76. // IsSet reports whether the preference has a value set.
  77. func (mv MapView[K, V]) IsSet() bool {
  78. return mv.ж.IsSet()
  79. }
  80. // Value returns a read-only view of the value if the preference has a value set.
  81. // Otherwise, it returns a read-only view of its default value.
  82. func (mv MapView[K, V]) Value() views.Map[K, V] {
  83. return views.MapOf(mv.ж.Value())
  84. }
  85. // ValueOk returns a read-only view of the value and true if the preference has a value set.
  86. // Otherwise, it returns an invalid view and false.
  87. func (mv MapView[K, V]) ValueOk() (val views.Map[K, V], ok bool) {
  88. if v, ok := mv.ж.ValueOk(); ok {
  89. return views.MapOf(v), true
  90. }
  91. return views.Map[K, V]{}, false
  92. }
  93. // DefaultValue returns a read-only view of the default value of the preference.
  94. func (mv MapView[K, V]) DefaultValue() views.Map[K, V] {
  95. return views.MapOf(mv.ж.DefaultValue())
  96. }
  97. // Managed reports whether the preference is managed via MDM, Group Policy, or similar means.
  98. func (mv MapView[K, V]) Managed() bool {
  99. return mv.ж.IsManaged()
  100. }
  101. // ReadOnly reports whether the preference is read-only and cannot be changed by user.
  102. func (mv MapView[K, V]) ReadOnly() bool {
  103. return mv.ж.IsReadOnly()
  104. }
  105. // Equal reports whether mv and mv2 are equal.
  106. func (mv MapView[K, V]) Equal(mv2 MapView[K, V]) bool {
  107. if !mv.Valid() && !mv2.Valid() {
  108. return true
  109. }
  110. if mv.Valid() != mv2.Valid() {
  111. return false
  112. }
  113. return mv.ж.Equal(*mv2.ж)
  114. }
  115. // MarshalJSONTo implements [jsonv2.MarshalerTo].
  116. func (mv MapView[K, V]) MarshalJSONTo(out *jsontext.Encoder) error {
  117. return mv.ж.MarshalJSONTo(out)
  118. }
  119. // UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom].
  120. func (mv *MapView[K, V]) UnmarshalJSONFrom(in *jsontext.Decoder) error {
  121. var x Map[K, V]
  122. if err := x.UnmarshalJSONFrom(in); err != nil {
  123. return err
  124. }
  125. mv.ж = &x
  126. return nil
  127. }
  128. // MarshalJSON implements [json.Marshaler].
  129. func (mv MapView[K, V]) MarshalJSON() ([]byte, error) {
  130. return jsonv2.Marshal(mv) // uses MarshalJSONTo
  131. }
  132. // UnmarshalJSON implements [json.Unmarshaler].
  133. func (mv *MapView[K, V]) UnmarshalJSON(b []byte) error {
  134. return jsonv2.Unmarshal(b, mv) // uses UnmarshalJSONFrom
  135. }