cmd/cloner, cmd/viewer: handle named map/slice types with Clone/View methods
The cloner and viewer code generators didn't handle named types
with basic underlying types (map/slice) that have their own Clone
or View methods. For example, a type like:
type Map map[string]any
func (m Map) Clone() Map { ... }
func (m Map) View() MapView { ... }
When used as a struct field, the cloner would descend into the
underlying map[string]any and fail because it can't clone the any
(interface{}) value type. Similarly, the viewer would try to create
a MapFnOf view and fail.
Fix the cloner to check for a Clone method on the named type
before falling through to the underlying type handling.
Fix the viewer to check for a View method on named map/slice types,
so the type author can provide a purpose-built safe view that
doesn't leak raw any values. Named map/slice types without a View
method fall through to normal handling, which correctly rejects
types like map[string]any as unsupported.
Updates tailscale/corp#39502 (needed by tailscale/corp#39594)
Change-Id: Iaef0192a221e02b4b8e409c99ef8398090327744
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
committed by
Brad Fitzpatrick
parent
5a899e406d
commit
86f42ea87b
@@ -12,7 +12,7 @@ import (
|
||||
"tailscale.com/types/views"
|
||||
)
|
||||
|
||||
//go:generate go run tailscale.com/cmd/viewer --type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices,OnlyGetClone,StructWithEmbedded,GenericIntStruct,GenericNoPtrsStruct,GenericCloneableStruct,StructWithContainers,StructWithTypeAliasFields,GenericTypeAliasStruct,StructWithMapOfViews --clone-only-type=OnlyGetClone
|
||||
//go:generate go run tailscale.com/cmd/viewer --type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices,OnlyGetClone,StructWithEmbedded,GenericIntStruct,GenericNoPtrsStruct,GenericCloneableStruct,StructWithContainers,StructWithTypeAliasFields,GenericTypeAliasStruct,StructWithMapOfViews,StructWithNamedMap,StructWithNamedSlice --clone-only-type=OnlyGetClone
|
||||
|
||||
type StructWithoutPtrs struct {
|
||||
Int int
|
||||
@@ -241,3 +241,61 @@ type GenericTypeAliasStruct[T integer, T2 views.ViewCloner[T2, V2], V2 views.Str
|
||||
type StructWithMapOfViews struct {
|
||||
MapOfViews map[string]StructWithoutPtrsView
|
||||
}
|
||||
|
||||
// NamedMap is a named map type with its own Clone and View methods.
|
||||
// This tests that the viewer calls View() on named map types rather
|
||||
// than trying to generate a view of the underlying map[string]any.
|
||||
type NamedMap map[string]any
|
||||
|
||||
func (m NamedMap) Clone() NamedMap {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
m2 := make(NamedMap, len(m))
|
||||
for k, v := range m {
|
||||
m2[k] = v
|
||||
}
|
||||
return m2
|
||||
}
|
||||
|
||||
// NamedMapView is a read-only view of NamedMap.
|
||||
type NamedMapView struct {
|
||||
ж NamedMap
|
||||
}
|
||||
|
||||
func (m NamedMap) View() NamedMapView { return NamedMapView{m} }
|
||||
|
||||
func (v NamedMapView) Get(k string) (any, bool) { val, ok := v.ж[k]; return val, ok }
|
||||
func (v NamedMapView) Len() int { return len(v.ж) }
|
||||
|
||||
type StructWithNamedMap struct {
|
||||
Attrs NamedMap
|
||||
}
|
||||
|
||||
// NamedSlice is a named slice type with its own Clone and View methods.
|
||||
// This tests that the viewer calls View() on named slice types rather
|
||||
// than trying to generate a view of the underlying []any.
|
||||
type NamedSlice []any
|
||||
|
||||
func (s NamedSlice) Clone() NamedSlice {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
s2 := make(NamedSlice, len(s))
|
||||
copy(s2, s)
|
||||
return s2
|
||||
}
|
||||
|
||||
// NamedSliceView is a read-only view of NamedSlice.
|
||||
type NamedSliceView struct {
|
||||
ж NamedSlice
|
||||
}
|
||||
|
||||
func (s NamedSlice) View() NamedSliceView { return NamedSliceView{s} }
|
||||
|
||||
func (v NamedSliceView) At(i int) any { return v.ж[i] }
|
||||
func (v NamedSliceView) Len() int { return len(v.ж) }
|
||||
|
||||
type StructWithNamedSlice struct {
|
||||
Items NamedSlice
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user