|
|
|
|
@ -9,6 +9,8 @@ package views |
|
|
|
|
import ( |
|
|
|
|
"encoding/json" |
|
|
|
|
"errors" |
|
|
|
|
"fmt" |
|
|
|
|
"reflect" |
|
|
|
|
|
|
|
|
|
"inet.af/netaddr" |
|
|
|
|
"tailscale.com/net/tsaddr" |
|
|
|
|
@ -97,8 +99,14 @@ type Slice[T any] struct { |
|
|
|
|
ж []T |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// SliceOf returns a Slice for the provided slice.
|
|
|
|
|
func SliceOf[T any](x []T) Slice[T] { return Slice[T]{x} } |
|
|
|
|
// SliceOf returns a Slice for the provided slice for immutable values.
|
|
|
|
|
// It panics if the value type contains pointers.
|
|
|
|
|
func SliceOf[T any](x []T) Slice[T] { |
|
|
|
|
if ev := reflect.TypeOf(x).Elem(); containsMutable(ev) { |
|
|
|
|
panic(fmt.Sprintf("slice value type %q has pointers", ev.Name())) |
|
|
|
|
} |
|
|
|
|
return Slice[T]{x} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// MarshalJSON implements json.Marshaler.
|
|
|
|
|
func (v Slice[T]) MarshalJSON() ([]byte, error) { |
|
|
|
|
@ -186,8 +194,52 @@ func (v *IPPrefixSlice) UnmarshalJSON(b []byte) error { |
|
|
|
|
return v.ж.UnmarshalJSON(b) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// MapOf returns a read-only view over m.
|
|
|
|
|
// containsMutable reports whether the provided type has anything mutable.
|
|
|
|
|
func containsMutable(t reflect.Type) bool { |
|
|
|
|
switch x := fmt.Sprintf("%v.%v", t.PkgPath(), t.Name()); x { |
|
|
|
|
case "time.Time", |
|
|
|
|
"inet.af/netaddr.IP": |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
k := t.Kind() |
|
|
|
|
switch k { |
|
|
|
|
case reflect.Bool, |
|
|
|
|
reflect.Int, |
|
|
|
|
reflect.Int8, |
|
|
|
|
reflect.Int16, |
|
|
|
|
reflect.Int32, |
|
|
|
|
reflect.Int64, |
|
|
|
|
reflect.Uint, |
|
|
|
|
reflect.Uint8, |
|
|
|
|
reflect.Uint16, |
|
|
|
|
reflect.Uint32, |
|
|
|
|
reflect.Uint64, |
|
|
|
|
reflect.Float32, |
|
|
|
|
reflect.Float64, |
|
|
|
|
reflect.Complex64, |
|
|
|
|
reflect.Complex128, |
|
|
|
|
reflect.String: |
|
|
|
|
return false |
|
|
|
|
case reflect.Array: // Not a slice.
|
|
|
|
|
return containsMutable(t.Elem()) && t.Len() > 0 |
|
|
|
|
case reflect.Struct: |
|
|
|
|
for i := 0; i < t.NumField(); i++ { |
|
|
|
|
f := t.Field(i) |
|
|
|
|
if containsMutable(f.Type) { |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
return true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// MapOf returns a read-only view over m for immutable values.
|
|
|
|
|
// It panics if the value type contains pointers.
|
|
|
|
|
func MapOf[K comparable, V comparable](m map[K]V) Map[K, V] { |
|
|
|
|
if ev := reflect.TypeOf(m).Elem(); containsMutable(ev) { |
|
|
|
|
panic(fmt.Sprintf("map value type %q has pointers", ev.Name())) |
|
|
|
|
} |
|
|
|
|
return Map[K, V]{m} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -226,10 +278,17 @@ func (m Map[K, V]) GetOk(k K) (V, bool) { |
|
|
|
|
return v, ok |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ForEach calls f for every k,v pair in the underlying map.
|
|
|
|
|
func (m Map[K, V]) ForEach(f func(k K, v V)) { |
|
|
|
|
// MapRangeFn is the func called from a Map.Range call.
|
|
|
|
|
// Implementations should return false to stop range.
|
|
|
|
|
type MapRangeFn[K comparable, V any] func(k K, v V) (cont bool) |
|
|
|
|
|
|
|
|
|
// Range calls f for every k,v pair in the underlying map.
|
|
|
|
|
// It stops iteration immediately if f returns false.
|
|
|
|
|
func (m Map[K, V]) Range(f MapRangeFn[K, V]) { |
|
|
|
|
for k, v := range m.ж { |
|
|
|
|
f(k, v) |
|
|
|
|
if !f(k, v) { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -278,9 +337,12 @@ func (m MapFn[K, T, V]) GetOk(k K) (V, bool) { |
|
|
|
|
return m.wrapv(v), ok |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ForEach calls f for every k,v pair in the underlying map.
|
|
|
|
|
func (m MapFn[K, T, V]) ForEach(f func(k K, v V)) { |
|
|
|
|
// Range calls f for every k,v pair in the underlying map.
|
|
|
|
|
// It stops iteration immediately if f returns false.
|
|
|
|
|
func (m MapFn[K, T, V]) Range(f MapRangeFn[K, V]) { |
|
|
|
|
for k, v := range m.ж { |
|
|
|
|
f(k, m.wrapv(v)) |
|
|
|
|
if !f(k, m.wrapv(v)) { |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|