mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-11 21:27:31 +00:00
cmd/viewer: add codegen tool for Views
Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
@@ -14,6 +14,78 @@ import (
|
||||
"tailscale.com/net/tsaddr"
|
||||
)
|
||||
|
||||
func unmarshalJSON[T any](b []byte, x *[]T) error {
|
||||
if *x != nil {
|
||||
return errors.New("already initialized")
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return nil
|
||||
}
|
||||
return json.Unmarshal(b, x)
|
||||
}
|
||||
|
||||
// StructView represents the corresponding StructView of a Viewable. The concrete types are
|
||||
// typically generated by tailscale.com/cmd/viewer.
|
||||
type StructView[T any] interface {
|
||||
// Valid reports whether the underlying Viewable is nil.
|
||||
Valid() bool
|
||||
// AsStruct returns a deep-copy of the underlying value.
|
||||
// It returns nil, if Valid() is false.
|
||||
AsStruct() T
|
||||
}
|
||||
|
||||
// ViewCloner is any type that has had View and Clone funcs generated using
|
||||
// tailscale.com/cmd/viewer.
|
||||
type ViewCloner[T any, V StructView[T]] interface {
|
||||
// View returns a read-only view of Viewable.
|
||||
// If Viewable is nil, View().Valid() reports false.
|
||||
View() V
|
||||
// Clone returns a deep-clone of Viewable.
|
||||
// It returns nil, when Viewable is nil.
|
||||
Clone() T
|
||||
}
|
||||
|
||||
// SliceOfViews returns a ViewSlice for x.
|
||||
func SliceOfViews[T ViewCloner[T, V], V StructView[T]](x []T) SliceView[T, V] {
|
||||
return SliceView[T, V]{x}
|
||||
}
|
||||
|
||||
// SliceView is a read-only wrapper around a struct which should only be exposed
|
||||
// as a View.
|
||||
type SliceView[T ViewCloner[T, V], V StructView[T]] struct {
|
||||
// It is named distinctively to make you think of how dangerous it is to escape
|
||||
// to callers. You must not let callers be able to mutate it.
|
||||
ж []T
|
||||
}
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
func (v SliceView[T, V]) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) }
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
func (v *SliceView[T, V]) UnmarshalJSON(b []byte) error { return unmarshalJSON(b, &v.ж) }
|
||||
|
||||
// IsNil reports whether the underlying slice is nil.
|
||||
func (v SliceView[T, V]) IsNil() bool { return v.ж == nil }
|
||||
|
||||
// Len returns the length of the slice.
|
||||
func (v SliceView[T, V]) Len() int { return len(v.ж) }
|
||||
|
||||
// At returns a View of the element at index `i` of the slice.
|
||||
func (v SliceView[T, V]) At(i int) V { return v.ж[i].View() }
|
||||
|
||||
// AppendTo appends the underlying slice values to dst.
|
||||
func (v SliceView[T, V]) AppendTo(dst []V) []V {
|
||||
for _, x := range v.ж {
|
||||
dst = append(dst, x.View())
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// AsSlice returns a copy of underlying slice.
|
||||
func (v SliceView[T, V]) AsSlice() []V {
|
||||
return v.AppendTo(nil)
|
||||
}
|
||||
|
||||
// Slice is a read-only accessor for a slice.
|
||||
type Slice[T any] struct {
|
||||
// It is named distinctively to make you think of how dangerous it is to escape
|
||||
@@ -31,16 +103,7 @@ func (v Slice[T]) MarshalJSON() ([]byte, error) {
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
func (v *Slice[T]) UnmarshalJSON(b []byte) error {
|
||||
if v.ж != nil {
|
||||
return errors.New("Slice is already initialized")
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return nil
|
||||
}
|
||||
if err := json.Unmarshal(b, &v.ж); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return unmarshalJSON(b, &v.ж)
|
||||
}
|
||||
|
||||
// IsNil reports whether the underlying slice is nil.
|
||||
|
Reference in New Issue
Block a user