This adds support for container-like types such as Container[T] that
don't explicitly specify a view type for T. Instead, a package implementing
a container type should also implement and export a ContainerView[T, V] type
and a ContainerViewOf(*Container[T]) ContainerView[T, V] function, which
returns a view for the specified container, inferring the element view type V
from the element type T.
Updates #12736
Signed-off-by: Nick Khyl <nickk@tailscale.com>
//go:generate go run tailscale.com/cmd/viewer --type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices,OnlyGetClone,StructWithEmbedded,GenericIntStruct,GenericNoPtrsStruct,GenericCloneableStruct --clone-only-type=OnlyGetClone
//go:generate go run tailscale.com/cmd/viewer --type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices,OnlyGetClone,StructWithEmbedded,GenericIntStruct,GenericNoPtrsStruct,GenericCloneableStruct,StructWithContainers --clone-only-type=OnlyGetClone
typeStructWithoutPtrsstruct{
typeStructWithoutPtrsstruct{
Intint
Intint
@ -114,3 +115,50 @@ type GenericCloneableStruct[T views.ViewCloner[T, V], V views.StructView[T]] str
PtrValueMapmap[string]*T
PtrValueMapmap[string]*T
SliceMapmap[string][]T
SliceMapmap[string][]T
}
}
// Container is a pre-defined container type, such as a collection, an optional
// value or a generic wrapper.
typeContainer[Tany]struct{
ItemT
}
func(c*Container[T])Clone()*Container[T]{
ifc==nil{
returnnil
}
ifcloner,ok:=any(c.Item).(views.Cloner[T]);ok{
return&Container[T]{cloner.Clone()}
}
if!views.ContainsPointers[T](){
returnptr.To(*c)
}
panic(fmt.Errorf("%T contains pointers, but is not cloneable",c.Item))
}
// ContainerView is a pre-defined readonly view of a Container[T].
//go:generate go run tailscale.com/cmd/cloner -clonefunc=false -type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices,OnlyGetClone,StructWithEmbedded,GenericIntStruct,GenericNoPtrsStruct,GenericCloneableStruct
//go:generate go run tailscale.com/cmd/cloner -clonefunc=false -type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices,OnlyGetClone,StructWithEmbedded,GenericIntStruct,GenericNoPtrsStruct,GenericCloneableStruct,StructWithContainers
// View returns a readonly view of StructWithPtrs.
// View returns a readonly view of StructWithPtrs.
func(p*StructWithPtrs)View()StructWithPtrsView{
func(p*StructWithPtrs)View()StructWithPtrsView{
@ -604,3 +604,67 @@ func _GenericCloneableStructViewNeedsRegeneration[T views.ViewCloner[T, V], V vi
SliceMapmap[string][]T
SliceMapmap[string][]T
}{})
}{})
}
}
// View returns a readonly view of StructWithContainers.
flagTypes=flag.String("type","","comma-separated list of types; required")
flagTypes=flag.String("type","","comma-separated list of types; required")
flagBuildTags=flag.String("tags","","compiler build tags to apply")
flagBuildTags=flag.String("tags","","compiler build tags to apply")
flagCloneFunc=flag.Bool("clonefunc",false,"add a top-level Clone func")
flagCloneFunc=flag.Bool("clonefunc",false,"add a top-level Clone func")
flagCloneOnlyTypes=flag.String("clone-only-type","","comma-separated list of types (a subset of --type) that should only generate a go:generate clone line and not actual views")
flagCloneOnlyTypes=flag.String("clone-only-type","","comma-separated list of types (a subset of --type) that should only generate a go:generate clone line and not actual views")