mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-25 11:05:45 +00:00
cmd/viewer: add support for map-like container types
This PR modifies viewTypeForContainerType to use the last type parameter of a container type as the value type, enabling the implementation of map-like container types where the second-to-last (usually first) type parameter serves as the key type. It also adds a MapContainer type to test the code generation. Updates #12736 Signed-off-by: Nick Khyl <nickk@tailscale.com>
This commit is contained in:
parent
2f27319baf
commit
f8f9f05ffe
@ -152,13 +152,53 @@ func ContainerViewOf[T views.ViewCloner[T, V], V views.StructView[T]](c *Contain
|
||||
return ContainerView[T, V]{c}
|
||||
}
|
||||
|
||||
// MapContainer is a predefined map-like container type.
|
||||
// Unlike [Container], it has two type parameters, where the value
|
||||
// is the second parameter.
|
||||
type MapContainer[K comparable, V views.Cloner[V]] struct {
|
||||
Items map[K]V
|
||||
}
|
||||
|
||||
func (c *MapContainer[K, V]) Clone() *MapContainer[K, V] {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
var m map[K]V
|
||||
if c.Items != nil {
|
||||
m = make(map[K]V, len(c.Items))
|
||||
for i := range m {
|
||||
m[i] = c.Items[i].Clone()
|
||||
}
|
||||
}
|
||||
return &MapContainer[K, V]{m}
|
||||
}
|
||||
|
||||
// MapContainerView is a pre-defined readonly view of a [MapContainer][K, T].
|
||||
type MapContainerView[K comparable, T views.ViewCloner[T, V], V views.StructView[T]] 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.
|
||||
ж *MapContainer[K, T]
|
||||
}
|
||||
|
||||
func (cv MapContainerView[K, T, V]) Items() views.MapFn[K, T, V] {
|
||||
return views.MapFnOf(cv.ж.Items, func(t T) V { return t.View() })
|
||||
}
|
||||
|
||||
func MapContainerViewOf[K comparable, T views.ViewCloner[T, V], V views.StructView[T]](c *MapContainer[K, T]) MapContainerView[K, T, V] {
|
||||
return MapContainerView[K, T, V]{c}
|
||||
}
|
||||
|
||||
type GenericBasicStruct[T BasicType] struct {
|
||||
Value T
|
||||
}
|
||||
|
||||
type StructWithContainers struct {
|
||||
IntContainer Container[int]
|
||||
CloneableContainer Container[*StructWithPtrs]
|
||||
BasicGenericContainer Container[GenericBasicStruct[int]]
|
||||
ClonableGenericContainer Container[*GenericNoPtrsStruct[int]]
|
||||
IntContainer Container[int]
|
||||
CloneableContainer Container[*StructWithPtrs]
|
||||
BasicGenericContainer Container[GenericBasicStruct[int]]
|
||||
CloneableGenericContainer Container[*GenericNoPtrsStruct[int]]
|
||||
CloneableMap MapContainer[int, *StructWithPtrs]
|
||||
CloneableGenericMap MapContainer[int, *GenericNoPtrsStruct[int]]
|
||||
}
|
||||
|
@ -426,14 +426,18 @@ func (src *StructWithContainers) Clone() *StructWithContainers {
|
||||
dst := new(StructWithContainers)
|
||||
*dst = *src
|
||||
dst.CloneableContainer = *src.CloneableContainer.Clone()
|
||||
dst.ClonableGenericContainer = *src.ClonableGenericContainer.Clone()
|
||||
dst.CloneableGenericContainer = *src.CloneableGenericContainer.Clone()
|
||||
dst.CloneableMap = *src.CloneableMap.Clone()
|
||||
dst.CloneableGenericMap = *src.CloneableGenericMap.Clone()
|
||||
return dst
|
||||
}
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _StructWithContainersCloneNeedsRegeneration = StructWithContainers(struct {
|
||||
IntContainer Container[int]
|
||||
CloneableContainer Container[*StructWithPtrs]
|
||||
BasicGenericContainer Container[GenericBasicStruct[int]]
|
||||
ClonableGenericContainer Container[*GenericNoPtrsStruct[int]]
|
||||
IntContainer Container[int]
|
||||
CloneableContainer Container[*StructWithPtrs]
|
||||
BasicGenericContainer Container[GenericBasicStruct[int]]
|
||||
CloneableGenericContainer Container[*GenericNoPtrsStruct[int]]
|
||||
CloneableMap MapContainer[int, *StructWithPtrs]
|
||||
CloneableGenericMap MapContainer[int, *GenericNoPtrsStruct[int]]
|
||||
}{})
|
||||
|
@ -657,14 +657,22 @@ func (v StructWithContainersView) CloneableContainer() ContainerView[*StructWith
|
||||
func (v StructWithContainersView) BasicGenericContainer() Container[GenericBasicStruct[int]] {
|
||||
return v.ж.BasicGenericContainer
|
||||
}
|
||||
func (v StructWithContainersView) ClonableGenericContainer() ContainerView[*GenericNoPtrsStruct[int], GenericNoPtrsStructView[int]] {
|
||||
return ContainerViewOf(&v.ж.ClonableGenericContainer)
|
||||
func (v StructWithContainersView) CloneableGenericContainer() ContainerView[*GenericNoPtrsStruct[int], GenericNoPtrsStructView[int]] {
|
||||
return ContainerViewOf(&v.ж.CloneableGenericContainer)
|
||||
}
|
||||
func (v StructWithContainersView) CloneableMap() MapContainerView[int, *StructWithPtrs, StructWithPtrsView] {
|
||||
return MapContainerViewOf(&v.ж.CloneableMap)
|
||||
}
|
||||
func (v StructWithContainersView) CloneableGenericMap() MapContainerView[int, *GenericNoPtrsStruct[int], GenericNoPtrsStructView[int]] {
|
||||
return MapContainerViewOf(&v.ж.CloneableGenericMap)
|
||||
}
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _StructWithContainersViewNeedsRegeneration = StructWithContainers(struct {
|
||||
IntContainer Container[int]
|
||||
CloneableContainer Container[*StructWithPtrs]
|
||||
BasicGenericContainer Container[GenericBasicStruct[int]]
|
||||
ClonableGenericContainer Container[*GenericNoPtrsStruct[int]]
|
||||
IntContainer Container[int]
|
||||
CloneableContainer Container[*StructWithPtrs]
|
||||
BasicGenericContainer Container[GenericBasicStruct[int]]
|
||||
CloneableGenericContainer Container[*GenericNoPtrsStruct[int]]
|
||||
CloneableMap MapContainer[int, *StructWithPtrs]
|
||||
CloneableGenericMap MapContainer[int, *GenericNoPtrsStruct[int]]
|
||||
}{})
|
||||
|
@ -448,7 +448,7 @@ func viewTypeForContainerType(typ types.Type) (*types.Named, *types.Func) {
|
||||
}
|
||||
// ...and add the element view type.
|
||||
// For that, we need to first determine the named elem type...
|
||||
elemType, ok := baseType(containerType.TypeArgs().At(0)).(*types.Named)
|
||||
elemType, ok := baseType(containerType.TypeArgs().At(containerType.TypeArgs().Len() - 1)).(*types.Named)
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user