mirror of
https://github.com/tailscale/tailscale.git
synced 2026-05-07 13:16:32 +02:00
cmd/viewer: add view-only option
This PR adds a --view-only-type flag to viewer to allow a type to be generated without a cloner. This is made available to make the few cases where writing a custom cloner is more practical, for example if the field is an interface. Updates corp/#16789 Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
parent
0e2cb76abe
commit
bbd65862d7
@ -9,7 +9,7 @@ import (
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
//go:generate go run tailscale.com/cmd/viewer --type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices,OnlyGetClone,StructWithEmbedded --clone-only-type=OnlyGetClone
|
||||
//go:generate go run tailscale.com/cmd/viewer --type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices,OnlyGetClone,OnlyGetView,StructWithEmbedded --clone-only-type=OnlyGetClone --view-only-type=OnlyGetView
|
||||
|
||||
type StructWithoutPtrs struct {
|
||||
Int int
|
||||
@ -62,6 +62,17 @@ type OnlyGetClone struct {
|
||||
SinViewerPorFavor bool
|
||||
}
|
||||
|
||||
type OnlyGetView struct {
|
||||
SinClonerPorFavor bool
|
||||
}
|
||||
|
||||
// Custom cloner func
|
||||
func (ogv *OnlyGetView) Clone() *OnlyGetView {
|
||||
return &OnlyGetView{
|
||||
SinClonerPorFavor: ogv.SinClonerPorFavor,
|
||||
}
|
||||
}
|
||||
|
||||
type StructWithEmbedded struct {
|
||||
A *StructWithPtrs
|
||||
StructWithSlices
|
||||
|
||||
@ -325,6 +325,58 @@ var _StructWithSlicesViewNeedsRegeneration = StructWithSlices(struct {
|
||||
Data []byte
|
||||
}{})
|
||||
|
||||
// View returns a readonly view of OnlyGetView.
|
||||
func (p *OnlyGetView) View() OnlyGetViewView {
|
||||
return OnlyGetViewView{ж: p}
|
||||
}
|
||||
|
||||
// OnlyGetViewView provides a read-only view over OnlyGetView.
|
||||
//
|
||||
// Its methods should only be called if `Valid()` returns true.
|
||||
type OnlyGetViewView 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.
|
||||
ж *OnlyGetView
|
||||
}
|
||||
|
||||
// Valid reports whether underlying value is non-nil.
|
||||
func (v OnlyGetViewView) Valid() bool { return v.ж != nil }
|
||||
|
||||
// AsStruct returns a clone of the underlying value which aliases no memory with
|
||||
// the original.
|
||||
func (v OnlyGetViewView) AsStruct() *OnlyGetView {
|
||||
if v.ж == nil {
|
||||
return nil
|
||||
}
|
||||
return v.ж.Clone()
|
||||
}
|
||||
|
||||
func (v OnlyGetViewView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) }
|
||||
|
||||
func (v *OnlyGetViewView) UnmarshalJSON(b []byte) error {
|
||||
if v.ж != nil {
|
||||
return errors.New("already initialized")
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return nil
|
||||
}
|
||||
var x OnlyGetView
|
||||
if err := json.Unmarshal(b, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
v.ж = &x
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v OnlyGetViewView) SinClonerPorFavor() bool { return v.ж.SinClonerPorFavor }
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _OnlyGetViewViewNeedsRegeneration = OnlyGetView(struct {
|
||||
SinClonerPorFavor bool
|
||||
}{})
|
||||
|
||||
// View returns a readonly view of StructWithEmbedded.
|
||||
func (p *StructWithEmbedded) View() StructWithEmbeddedView {
|
||||
return StructWithEmbeddedView{ж: p}
|
||||
|
||||
@ -40,7 +40,7 @@ func (v {{.ViewName}}) Valid() bool { return v.ж != nil }
|
||||
|
||||
// AsStruct returns a clone of the underlying value which aliases no memory with
|
||||
// the original.
|
||||
func (v {{.ViewName}}) AsStruct() *{{.StructName}}{
|
||||
func (v {{.ViewName}}) AsStruct() *{{.StructName}}{
|
||||
if v.ж == nil {
|
||||
return nil
|
||||
}
|
||||
@ -324,6 +324,7 @@ var (
|
||||
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")
|
||||
flagViewOnlyTypes = flag.String("view-only-type", "", "comma-separated list of types (a subset of --type) that should only generate views and not be added to go:generate for cloner")
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -336,10 +337,21 @@ func main() {
|
||||
}
|
||||
typeNames := strings.Split(*flagTypes, ",")
|
||||
|
||||
viewOnlyTypes := map[string]bool{}
|
||||
for _, t := range strings.Split(*flagViewOnlyTypes, ",") {
|
||||
viewOnlyTypes[t] = true
|
||||
}
|
||||
|
||||
var flagArgs []string
|
||||
flagArgs = append(flagArgs, fmt.Sprintf("-clonefunc=%v", *flagCloneFunc))
|
||||
if *flagTypes != "" {
|
||||
flagArgs = append(flagArgs, "-type="+*flagTypes)
|
||||
var cloneTypes []string
|
||||
for _, t := range strings.Split(*flagTypes, ",") {
|
||||
if _, ok := viewOnlyTypes[t]; !ok {
|
||||
cloneTypes = append(cloneTypes, t)
|
||||
}
|
||||
}
|
||||
flagArgs = append(flagArgs, "-type="+strings.Join(cloneTypes, ","))
|
||||
}
|
||||
if *flagBuildTags != "" {
|
||||
flagArgs = append(flagArgs, "-tags="+*flagBuildTags)
|
||||
@ -373,7 +385,7 @@ func main() {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasClone {
|
||||
if !hasClone && !viewOnlyTypes[typeName] {
|
||||
runCloner = true
|
||||
}
|
||||
genView(buf, it, typ, pkg.Types)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user