summaryrefslogtreecommitdiffhomepage
path: root/cmd
diff options
context:
space:
mode:
authorMaisem Ali <maisem@tailscale.com>2022-05-09 09:30:39 -0700
committerMaisem Ali <maisem@gmail.com>2022-05-09 19:49:31 -0700
commitd04afc697cbb81fb765fdee8847b8e33e34537be (patch)
tree5a0b409f9f7dd7a9cae5335b3488b4ab5fbb3700 /cmd
parent5cd56fe8d5f9585ef130dde4b7aa04eaf201685a (diff)
downloadtailscale-d04afc697cbb81fb765fdee8847b8e33e34537be.tar.xz
tailscale-d04afc697cbb81fb765fdee8847b8e33e34537be.zip
cmd/viewer,types/views: add support for views of maps
Updates #4635 Signed-off-by: Maisem Ali <maisem@tailscale.com>
Diffstat (limited to 'cmd')
-rw-r--r--cmd/viewer/tests/tests.go13
-rw-r--r--cmd/viewer/tests/tests_clone.go73
-rw-r--r--cmd/viewer/tests/tests_view.go50
-rw-r--r--cmd/viewer/viewer.go74
4 files changed, 197 insertions, 13 deletions
diff --git a/cmd/viewer/tests/tests.go b/cmd/viewer/tests/tests.go
index 18115ea0f..ec202ccde 100644
--- a/cmd/viewer/tests/tests.go
+++ b/cmd/viewer/tests/tests.go
@@ -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 {
diff --git a/cmd/viewer/tests/tests_clone.go b/cmd/viewer/tests/tests_clone.go
index 1fb12746f..357fa20a5 100644
--- a/cmd/viewer/tests/tests_clone.go
+++ b/cmd/viewer/tests/tests_clone.go
@@ -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.
diff --git a/cmd/viewer/tests/tests_view.go b/cmd/viewer/tests/tests_view.go
index a3abe6f1e..30d6b1af3 100644
--- a/cmd/viewer/tests/tests_view.go
+++ b/cmd/viewer/tests/tests_view.go
@@ -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.
diff --git a/cmd/viewer/viewer.go b/cmd/viewer/viewer.go
index ad3f02696..c9909453a 100644
--- a/cmd/viewer/viewer.go
+++ b/cmd/viewer/viewer.go
@@ -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