mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-11 21:27:31 +00:00
types/views,cmd/viewer: add ByteSlice[T] to replace mem.RO
Add a new views.ByteSlice[T ~[]byte] to provide a better API to use with views. Updates #cleanup Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
@@ -6,9 +6,12 @@
|
||||
package views
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"maps"
|
||||
|
||||
"go4.org/mem"
|
||||
)
|
||||
|
||||
func unmarshalSliceFromJSON[T any](b []byte, x *[]T) error {
|
||||
@@ -21,6 +24,83 @@ func unmarshalSliceFromJSON[T any](b []byte, x *[]T) error {
|
||||
return json.Unmarshal(b, x)
|
||||
}
|
||||
|
||||
// ByteSlice is a read-only accessor for types that are backed by a []byte.
|
||||
type ByteSlice[T ~[]byte] struct {
|
||||
// ж is the underlying mutable value, named with a hard-to-type
|
||||
// character that looks pointy like a pointer.
|
||||
// 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
|
||||
}
|
||||
|
||||
// ByteSliceOf returns a ByteSlice for the provided slice.
|
||||
func ByteSliceOf[T ~[]byte](x T) ByteSlice[T] {
|
||||
return ByteSlice[T]{x}
|
||||
}
|
||||
|
||||
// Len returns the length of the slice.
|
||||
func (v ByteSlice[T]) Len() int {
|
||||
return len(v.ж)
|
||||
}
|
||||
|
||||
// IsNil reports whether the underlying slice is nil.
|
||||
func (v ByteSlice[T]) IsNil() bool {
|
||||
return v.ж == nil
|
||||
}
|
||||
|
||||
// Mem returns a read-only view of the underlying slice.
|
||||
func (v ByteSlice[T]) Mem() mem.RO {
|
||||
return mem.B(v.ж)
|
||||
}
|
||||
|
||||
// Equal reports whether the underlying slice is equal to b.
|
||||
func (v ByteSlice[T]) Equal(b T) bool {
|
||||
return bytes.Equal(v.ж, b)
|
||||
}
|
||||
|
||||
// EqualView reports whether the underlying slice is equal to b.
|
||||
func (v ByteSlice[T]) EqualView(b ByteSlice[T]) bool {
|
||||
return bytes.Equal(v.ж, b.ж)
|
||||
}
|
||||
|
||||
// AsSlice returns a copy of the underlying slice.
|
||||
func (v ByteSlice[T]) AsSlice() T {
|
||||
return v.AppendTo(v.ж[:0:0])
|
||||
}
|
||||
|
||||
// AppendTo appends the underlying slice values to dst.
|
||||
func (v ByteSlice[T]) AppendTo(dst T) T {
|
||||
return append(dst, v.ж...)
|
||||
}
|
||||
|
||||
// LenIter returns a slice the same length as the v.Len().
|
||||
// The caller can then range over it to get the valid indexes.
|
||||
// It does not allocate.
|
||||
func (v ByteSlice[T]) LenIter() []struct{} { return make([]struct{}, len(v.ж)) }
|
||||
|
||||
// At returns the byte at index `i` of the slice.
|
||||
func (v ByteSlice[T]) At(i int) byte { return v.ж[i] }
|
||||
|
||||
// SliceFrom returns v[i:].
|
||||
func (v ByteSlice[T]) SliceFrom(i int) ByteSlice[T] { return ByteSlice[T]{v.ж[i:]} }
|
||||
|
||||
// SliceTo returns v[:i]
|
||||
func (v ByteSlice[T]) SliceTo(i int) ByteSlice[T] { return ByteSlice[T]{v.ж[:i]} }
|
||||
|
||||
// Slice returns v[i:j]
|
||||
func (v ByteSlice[T]) Slice(i, j int) ByteSlice[T] { return ByteSlice[T]{v.ж[i:j]} }
|
||||
|
||||
// MarshalJSON implements json.Marshaler.
|
||||
func (v ByteSlice[T]) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) }
|
||||
|
||||
// UnmarshalJSON implements json.Unmarshaler.
|
||||
func (v *ByteSlice[T]) UnmarshalJSON(b []byte) error {
|
||||
if v.ж != nil {
|
||||
return errors.New("already initialized")
|
||||
}
|
||||
return json.Unmarshal(b, &v.ж)
|
||||
}
|
||||
|
||||
// StructView represents the corresponding StructView of a Viewable. The concrete types are
|
||||
// typically generated by tailscale.com/cmd/viewer.
|
||||
type StructView[T any] interface {
|
||||
@@ -47,8 +127,9 @@ 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.
|
||||
// SliceView wraps []T to provide accessors which return an immutable view V of
|
||||
// T. It is used to provide the equivalent of SliceOf([]V) without having to
|
||||
// allocate []V from []T.
|
||||
type SliceView[T ViewCloner[T, V], V StructView[T]] struct {
|
||||
// ж is the underlying mutable value, named with a hard-to-type
|
||||
// character that looks pointy like a pointer.
|
||||
|
Reference in New Issue
Block a user