mirror of
https://github.com/tailscale/tailscale.git
synced 2025-01-08 09:07:44 +00:00
util/codegen: support embedded fields
I noticed cmd/{cloner,viewer} didn't support structs with embedded fields while working on a change in another repo. This adds support. Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
parent
ea84fc9ad2
commit
4f454f4122
@ -9,7 +9,7 @@
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run tailscale.com/cmd/viewer --type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices,OnlyGetClone --clone-only-type=OnlyGetClone
|
//go:generate go run tailscale.com/cmd/viewer --type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices,OnlyGetClone,StructWithEmbedded --clone-only-type=OnlyGetClone
|
||||||
|
|
||||||
type StructWithoutPtrs struct {
|
type StructWithoutPtrs struct {
|
||||||
Int int
|
Int int
|
||||||
@ -61,3 +61,8 @@ type StructWithSlices struct {
|
|||||||
type OnlyGetClone struct {
|
type OnlyGetClone struct {
|
||||||
SinViewerPorFavor bool
|
SinViewerPorFavor bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StructWithEmbedded struct {
|
||||||
|
A *StructWithPtrs
|
||||||
|
StructWithSlices
|
||||||
|
}
|
||||||
|
@ -211,3 +211,22 @@ func (src *OnlyGetClone) Clone() *OnlyGetClone {
|
|||||||
var _OnlyGetCloneCloneNeedsRegeneration = OnlyGetClone(struct {
|
var _OnlyGetCloneCloneNeedsRegeneration = OnlyGetClone(struct {
|
||||||
SinViewerPorFavor bool
|
SinViewerPorFavor bool
|
||||||
}{})
|
}{})
|
||||||
|
|
||||||
|
// Clone makes a deep copy of StructWithEmbedded.
|
||||||
|
// The result aliases no memory with the original.
|
||||||
|
func (src *StructWithEmbedded) Clone() *StructWithEmbedded {
|
||||||
|
if src == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
dst := new(StructWithEmbedded)
|
||||||
|
*dst = *src
|
||||||
|
dst.A = src.A.Clone()
|
||||||
|
dst.StructWithSlices = *src.StructWithSlices.Clone()
|
||||||
|
return dst
|
||||||
|
}
|
||||||
|
|
||||||
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||||
|
var _StructWithEmbeddedCloneNeedsRegeneration = StructWithEmbedded(struct {
|
||||||
|
A *StructWithPtrs
|
||||||
|
StructWithSlices
|
||||||
|
}{})
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
"tailscale.com/types/views"
|
"tailscale.com/types/views"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run tailscale.com/cmd/cloner -clonefunc=false -type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices,OnlyGetClone
|
//go:generate go run tailscale.com/cmd/cloner -clonefunc=false -type=StructWithPtrs,StructWithoutPtrs,Map,StructWithSlices,OnlyGetClone,StructWithEmbedded
|
||||||
|
|
||||||
// View returns a readonly view of StructWithPtrs.
|
// View returns a readonly view of StructWithPtrs.
|
||||||
func (p *StructWithPtrs) View() StructWithPtrsView {
|
func (p *StructWithPtrs) View() StructWithPtrsView {
|
||||||
@ -325,3 +325,59 @@ func (v StructWithSlicesView) Data() mem.RO { return mem.B(v.ж.Data) }
|
|||||||
Prefixes []netip.Prefix
|
Prefixes []netip.Prefix
|
||||||
Data []byte
|
Data []byte
|
||||||
}{})
|
}{})
|
||||||
|
|
||||||
|
// View returns a readonly view of StructWithEmbedded.
|
||||||
|
func (p *StructWithEmbedded) View() StructWithEmbeddedView {
|
||||||
|
return StructWithEmbeddedView{ж: p}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StructWithEmbeddedView provides a read-only view over StructWithEmbedded.
|
||||||
|
//
|
||||||
|
// Its methods should only be called if `Valid()` returns true.
|
||||||
|
type StructWithEmbeddedView 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.
|
||||||
|
ж *StructWithEmbedded
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid reports whether underlying value is non-nil.
|
||||||
|
func (v StructWithEmbeddedView) Valid() bool { return v.ж != nil }
|
||||||
|
|
||||||
|
// AsStruct returns a clone of the underlying value which aliases no memory with
|
||||||
|
// the original.
|
||||||
|
func (v StructWithEmbeddedView) AsStruct() *StructWithEmbedded {
|
||||||
|
if v.ж == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return v.ж.Clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v StructWithEmbeddedView) MarshalJSON() ([]byte, error) { return json.Marshal(v.ж) }
|
||||||
|
|
||||||
|
func (v *StructWithEmbeddedView) UnmarshalJSON(b []byte) error {
|
||||||
|
if v.ж != nil {
|
||||||
|
return errors.New("already initialized")
|
||||||
|
}
|
||||||
|
if len(b) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var x StructWithEmbedded
|
||||||
|
if err := json.Unmarshal(b, &x); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.ж = &x
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v StructWithEmbeddedView) A() StructWithPtrsView { return v.ж.A.View() }
|
||||||
|
func (v StructWithEmbeddedView) StructWithSlices() StructWithSlicesView {
|
||||||
|
return v.ж.StructWithSlices.View()
|
||||||
|
}
|
||||||
|
|
||||||
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||||
|
var _StructWithEmbeddedViewNeedsRegeneration = StructWithEmbedded(struct {
|
||||||
|
A *StructWithPtrs
|
||||||
|
StructWithSlices
|
||||||
|
}{})
|
||||||
|
@ -202,14 +202,19 @@ func AssertStructUnchanged(t *types.Struct, tname, ctx string, it *ImportTracker
|
|||||||
w("var _%s%sNeedsRegeneration = %s(struct {", tname, ctx, tname)
|
w("var _%s%sNeedsRegeneration = %s(struct {", tname, ctx, tname)
|
||||||
|
|
||||||
for i := 0; i < t.NumFields(); i++ {
|
for i := 0; i < t.NumFields(); i++ {
|
||||||
fname := t.Field(i).Name()
|
st := t.Field(i)
|
||||||
|
fname := st.Name()
|
||||||
ft := t.Field(i).Type()
|
ft := t.Field(i).Type()
|
||||||
if IsInvalid(ft) {
|
if IsInvalid(ft) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
qname := it.QualifiedName(ft)
|
qname := it.QualifiedName(ft)
|
||||||
|
if st.Anonymous() {
|
||||||
|
w("\t%s ", fname)
|
||||||
|
} else {
|
||||||
w("\t%s %s", fname, qname)
|
w("\t%s %s", fname, qname)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
w("}{})\n")
|
w("}{})\n")
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user