diff options
| author | Maisem Ali <maisem@tailscale.com> | 2022-05-09 09:30:39 -0700 |
|---|---|---|
| committer | Maisem Ali <maisem@gmail.com> | 2022-05-09 19:49:31 -0700 |
| commit | d04afc697cbb81fb765fdee8847b8e33e34537be (patch) | |
| tree | 5a0b409f9f7dd7a9cae5335b3488b4ab5fbb3700 /cmd | |
| parent | 5cd56fe8d5f9585ef130dde4b7aa04eaf201685a (diff) | |
| download | tailscale-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.go | 13 | ||||
| -rw-r--r-- | cmd/viewer/tests/tests_clone.go | 73 | ||||
| -rw-r--r-- | cmd/viewer/tests/tests_view.go | 50 | ||||
| -rw-r--r-- | cmd/viewer/viewer.go | 74 |
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 |
