mirror of
https://github.com/tailscale/tailscale.git
synced 2025-08-22 11:01:54 +00:00
cmd/viewer,types/views: add support for views of maps
Updates #4635 Signed-off-by: Maisem Ali <maisem@tailscale.com>
This commit is contained in:
@@ -19,7 +19,18 @@ type StructWithoutPtrs struct {
|
||||
}
|
||||
|
||||
type Map struct {
|
||||
M map[string]int
|
||||
Int map[string]int
|
||||
SliceInt map[string][]int
|
||||
StructWithPtr map[string]*StructWithPtrs
|
||||
StructWithoutPtr map[string]*StructWithoutPtrs
|
||||
SlicesWithPtrs map[string][]*StructWithPtrs
|
||||
SlicesWithoutPtrs map[string][]*StructWithoutPtrs
|
||||
StructWithoutPtrKey map[StructWithoutPtrs]int `json:"-"`
|
||||
|
||||
// Unsupported.
|
||||
SliceIntPtr map[string][]*int
|
||||
PointerKey map[*string]int `json:"-"`
|
||||
StructWithPtrKey map[StructWithPtrs]int `json:"-"`
|
||||
}
|
||||
|
||||
type StructWithPtrs struct {
|
||||
|
@@ -61,10 +61,64 @@ func (src *Map) Clone() *Map {
|
||||
}
|
||||
dst := new(Map)
|
||||
*dst = *src
|
||||
if dst.M != nil {
|
||||
dst.M = map[string]int{}
|
||||
for k, v := range src.M {
|
||||
dst.M[k] = v
|
||||
if dst.Int != nil {
|
||||
dst.Int = map[string]int{}
|
||||
for k, v := range src.Int {
|
||||
dst.Int[k] = v
|
||||
}
|
||||
}
|
||||
if dst.SliceInt != nil {
|
||||
dst.SliceInt = map[string][]int{}
|
||||
for k := range src.SliceInt {
|
||||
dst.SliceInt[k] = append([]int{}, src.SliceInt[k]...)
|
||||
}
|
||||
}
|
||||
if dst.StructWithPtr != nil {
|
||||
dst.StructWithPtr = map[string]*StructWithPtrs{}
|
||||
for k, v := range src.StructWithPtr {
|
||||
dst.StructWithPtr[k] = v.Clone()
|
||||
}
|
||||
}
|
||||
if dst.StructWithoutPtr != nil {
|
||||
dst.StructWithoutPtr = map[string]*StructWithoutPtrs{}
|
||||
for k, v := range src.StructWithoutPtr {
|
||||
dst.StructWithoutPtr[k] = v.Clone()
|
||||
}
|
||||
}
|
||||
if dst.SlicesWithPtrs != nil {
|
||||
dst.SlicesWithPtrs = map[string][]*StructWithPtrs{}
|
||||
for k := range src.SlicesWithPtrs {
|
||||
dst.SlicesWithPtrs[k] = append([]*StructWithPtrs{}, src.SlicesWithPtrs[k]...)
|
||||
}
|
||||
}
|
||||
if dst.SlicesWithoutPtrs != nil {
|
||||
dst.SlicesWithoutPtrs = map[string][]*StructWithoutPtrs{}
|
||||
for k := range src.SlicesWithoutPtrs {
|
||||
dst.SlicesWithoutPtrs[k] = append([]*StructWithoutPtrs{}, src.SlicesWithoutPtrs[k]...)
|
||||
}
|
||||
}
|
||||
if dst.StructWithoutPtrKey != nil {
|
||||
dst.StructWithoutPtrKey = map[StructWithoutPtrs]int{}
|
||||
for k, v := range src.StructWithoutPtrKey {
|
||||
dst.StructWithoutPtrKey[k] = v
|
||||
}
|
||||
}
|
||||
if dst.SliceIntPtr != nil {
|
||||
dst.SliceIntPtr = map[string][]*int{}
|
||||
for k := range src.SliceIntPtr {
|
||||
dst.SliceIntPtr[k] = append([]*int{}, src.SliceIntPtr[k]...)
|
||||
}
|
||||
}
|
||||
if dst.PointerKey != nil {
|
||||
dst.PointerKey = map[*string]int{}
|
||||
for k, v := range src.PointerKey {
|
||||
dst.PointerKey[k] = v
|
||||
}
|
||||
}
|
||||
if dst.StructWithPtrKey != nil {
|
||||
dst.StructWithPtrKey = map[StructWithPtrs]int{}
|
||||
for k, v := range src.StructWithPtrKey {
|
||||
dst.StructWithPtrKey[k] = v
|
||||
}
|
||||
}
|
||||
return dst
|
||||
@@ -72,7 +126,16 @@ func (src *Map) Clone() *Map {
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _MapCloneNeedsRegeneration = Map(struct {
|
||||
M map[string]int
|
||||
Int map[string]int
|
||||
SliceInt map[string][]int
|
||||
StructWithPtr map[string]*StructWithPtrs
|
||||
StructWithoutPtr map[string]*StructWithoutPtrs
|
||||
SlicesWithPtrs map[string][]*StructWithPtrs
|
||||
SlicesWithoutPtrs map[string][]*StructWithoutPtrs
|
||||
StructWithoutPtrKey map[StructWithoutPtrs]int
|
||||
SliceIntPtr map[string][]*int
|
||||
PointerKey map[*string]int
|
||||
StructWithPtrKey map[StructWithPtrs]int
|
||||
}{})
|
||||
|
||||
// Clone makes a deep copy of StructWithSlices.
|
||||
|
@@ -188,9 +188,57 @@ func (v *MapView) UnmarshalJSON(b []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v MapView) Int() views.Map[string, int] { return views.MapOf(v.ж.Int) }
|
||||
|
||||
func (v MapView) SliceInt() views.MapFn[string, []int, views.Slice[int]] {
|
||||
return views.MapFnOf(v.ж.SliceInt, func(t []int) views.Slice[int] {
|
||||
return views.SliceOf(t)
|
||||
})
|
||||
}
|
||||
|
||||
func (v MapView) StructWithPtr() views.MapFn[string, *StructWithPtrs, StructWithPtrsView] {
|
||||
return views.MapFnOf(v.ж.StructWithPtr, func(t *StructWithPtrs) StructWithPtrsView {
|
||||
return t.View()
|
||||
})
|
||||
}
|
||||
|
||||
func (v MapView) StructWithoutPtr() views.MapFn[string, *StructWithoutPtrs, StructWithoutPtrsView] {
|
||||
return views.MapFnOf(v.ж.StructWithoutPtr, func(t *StructWithoutPtrs) StructWithoutPtrsView {
|
||||
return t.View()
|
||||
})
|
||||
}
|
||||
|
||||
func (v MapView) SlicesWithPtrs() views.MapFn[string, []*StructWithPtrs, views.SliceView[*StructWithPtrs, StructWithPtrsView]] {
|
||||
return views.MapFnOf(v.ж.SlicesWithPtrs, func(t []*StructWithPtrs) views.SliceView[*StructWithPtrs, StructWithPtrsView] {
|
||||
return views.SliceOfViews[*StructWithPtrs, StructWithPtrsView](t)
|
||||
})
|
||||
}
|
||||
|
||||
func (v MapView) SlicesWithoutPtrs() views.MapFn[string, []*StructWithoutPtrs, views.SliceView[*StructWithoutPtrs, StructWithoutPtrsView]] {
|
||||
return views.MapFnOf(v.ж.SlicesWithoutPtrs, func(t []*StructWithoutPtrs) views.SliceView[*StructWithoutPtrs, StructWithoutPtrsView] {
|
||||
return views.SliceOfViews[*StructWithoutPtrs, StructWithoutPtrsView](t)
|
||||
})
|
||||
}
|
||||
|
||||
func (v MapView) StructWithoutPtrKey() views.Map[StructWithoutPtrs, int] {
|
||||
return views.MapOf(v.ж.StructWithoutPtrKey)
|
||||
}
|
||||
func (v MapView) SliceIntPtr() map[string][]*int { panic("unsupported") }
|
||||
func (v MapView) PointerKey() map[*string]int { panic("unsupported") }
|
||||
func (v MapView) StructWithPtrKey() map[StructWithPtrs]int { panic("unsupported") }
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _MapViewNeedsRegeneration = Map(struct {
|
||||
M map[string]int
|
||||
Int map[string]int
|
||||
SliceInt map[string][]int
|
||||
StructWithPtr map[string]*StructWithPtrs
|
||||
StructWithoutPtr map[string]*StructWithoutPtrs
|
||||
SlicesWithPtrs map[string][]*StructWithPtrs
|
||||
SlicesWithoutPtrs map[string][]*StructWithoutPtrs
|
||||
StructWithoutPtrKey map[StructWithoutPtrs]int
|
||||
SliceIntPtr map[string][]*int
|
||||
PointerKey map[*string]int
|
||||
StructWithPtrKey map[StructWithPtrs]int
|
||||
}{})
|
||||
|
||||
// View returns a readonly view of StructWithSlices.
|
||||
|
@@ -88,8 +88,12 @@ func (v *{{.ViewName}}) UnmarshalJSON(b []byte) error {
|
||||
|
||||
{{end}}
|
||||
{{define "mapField"}}
|
||||
// Unsupported, panics.
|
||||
func(v {{.ViewName}}) {{.FieldName}}() {{.FieldType}} {panic("unsupported")}
|
||||
func(v {{.ViewName}}) {{.FieldName}}() views.Map[{{.MapKeyType}},{{.MapValueType}}] { return views.MapOf(v.ж.{{.FieldName}})}
|
||||
{{end}}
|
||||
{{define "mapFnField"}}
|
||||
func(v {{.ViewName}}) {{.FieldName}}() views.MapFn[{{.MapKeyType}},{{.MapValueType}},{{.MapValueView}}] { return views.MapFnOf(v.ж.{{.FieldName}}, func (t {{.MapValueType}}) {{.MapValueView}} {
|
||||
return {{.MapFn}}
|
||||
})}
|
||||
{{end}}
|
||||
{{define "unsupportedField"}}func(v {{.ViewName}}) {{.FieldName}}() {{.FieldType}} {panic("unsupported")}
|
||||
{{end}}
|
||||
@@ -132,6 +136,11 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, thi
|
||||
FieldName string
|
||||
FieldType string
|
||||
FieldViewName string
|
||||
|
||||
MapKeyType string
|
||||
MapValueType string
|
||||
MapValueView string
|
||||
MapFn string
|
||||
}{
|
||||
StructName: typ.Obj().Name(),
|
||||
ViewName: typ.Obj().Name() + "View",
|
||||
@@ -194,7 +203,7 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, thi
|
||||
writeTemplate("sliceField")
|
||||
}
|
||||
continue
|
||||
case *types.Struct:
|
||||
case *types.Struct, *types.Named:
|
||||
strucT := underlying
|
||||
args.FieldType = it.QualifiedName(fieldType)
|
||||
if codegen.ContainsPointers(strucT) {
|
||||
@@ -204,9 +213,62 @@ func genView(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named, thi
|
||||
writeTemplate("valueField")
|
||||
continue
|
||||
case *types.Map:
|
||||
// TODO(maisem): support this.
|
||||
// args.FieldType = importedName(ft)
|
||||
// writeTemplate("mapField")
|
||||
m := underlying
|
||||
args.FieldType = it.QualifiedName(fieldType)
|
||||
shallow, deep, key := requiresCloning(m.Key())
|
||||
if shallow || deep {
|
||||
writeTemplate("unsupportedField")
|
||||
continue
|
||||
}
|
||||
args.MapKeyType = it.QualifiedName(key)
|
||||
mElem := m.Elem()
|
||||
var template string
|
||||
switch u := mElem.(type) {
|
||||
case *types.Basic:
|
||||
template = "mapField"
|
||||
args.MapValueType = it.QualifiedName(mElem)
|
||||
case *types.Slice:
|
||||
slice := u
|
||||
sElem := slice.Elem()
|
||||
switch x := sElem.(type) {
|
||||
case *types.Basic:
|
||||
args.MapValueView = fmt.Sprintf("views.Slice[%v]", sElem)
|
||||
args.MapValueType = "[]" + sElem.String()
|
||||
args.MapFn = "views.SliceOf(t)"
|
||||
template = "mapFnField"
|
||||
case *types.Pointer:
|
||||
ptr := x
|
||||
pElem := ptr.Elem()
|
||||
switch pElem.(type) {
|
||||
case *types.Struct, *types.Named:
|
||||
ptrType := it.QualifiedName(ptr)
|
||||
viewType := it.QualifiedName(pElem) + "View"
|
||||
args.MapFn = fmt.Sprintf("views.SliceOfViews[%v,%v](t)", ptrType, viewType)
|
||||
args.MapValueView = fmt.Sprintf("views.SliceView[%v,%v]", ptrType, viewType)
|
||||
args.MapValueType = "[]" + ptrType
|
||||
template = "mapFnField"
|
||||
default:
|
||||
template = "unsupportedField"
|
||||
}
|
||||
default:
|
||||
template = "unsupportedField"
|
||||
}
|
||||
case *types.Pointer:
|
||||
ptr := u
|
||||
pElem := ptr.Elem()
|
||||
switch pElem.(type) {
|
||||
case *types.Struct, *types.Named:
|
||||
args.MapValueType = it.QualifiedName(ptr)
|
||||
args.MapValueView = it.QualifiedName(pElem) + "View"
|
||||
args.MapFn = "t.View()"
|
||||
template = "mapFnField"
|
||||
default:
|
||||
template = "unsupportedField"
|
||||
}
|
||||
default:
|
||||
template = "unsupportedField"
|
||||
}
|
||||
writeTemplate(template)
|
||||
continue
|
||||
case *types.Pointer:
|
||||
ptr := underlying
|
||||
|
Reference in New Issue
Block a user