mirror of
https://github.com/tailscale/tailscale.git
synced 2026-07-20 21:23:07 +08:00
cmd/cloner: handle named slices as map values (#20387)
Previously cloner only handled literal slices for values, like `map[string][]int`. This adds support for named types with an underlying type of slice, like `map[string]IntSlice` with `type IntSlice []int`. Updates tailscale/corp#44077 Signed-off-by: Andrew Lytvynov <awly@tailscale.com>
This commit is contained in:
parent
0e79b322a9
commit
3872880617
@ -169,7 +169,7 @@ func gen(buf *bytes.Buffer, it *codegen.ImportTracker, typ *types.Named) {
|
||||
writef("}")
|
||||
case *types.Map:
|
||||
elem := ft.Elem()
|
||||
if sliceType, isSlice := elem.(*types.Slice); isSlice {
|
||||
if sliceType, isSlice := elem.Underlying().(*types.Slice); isSlice {
|
||||
n := it.QualifiedName(sliceType.Elem())
|
||||
writef("if dst.%s != nil {", fname)
|
||||
writef("\tdst.%s = map[%s]%s{}", fname, it.QualifiedName(ft.Key()), it.QualifiedName(elem))
|
||||
|
||||
@ -283,3 +283,13 @@ func TestDeeplyNestedMap(t *testing.T) {
|
||||
t.Errorf("Clone() aliased FourLevels map: new nested key appeared in original")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMapWithNamedSliceValues(t *testing.T) {
|
||||
orig := &clonerex.MapWithNamedSliceValues{
|
||||
M: map[string]clonerex.NamedSlice{"k": {"foo", "bar"}},
|
||||
}
|
||||
cloned := orig.Clone()
|
||||
if diff := cmp.Diff(orig, cloned); diff != "" {
|
||||
t.Errorf("Clone() mismatch (-orig +cloned):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Copyright (c) Tailscale Inc & contributors
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:generate go run tailscale.com/cmd/cloner -clonefunc=true -type SliceContainer,InterfaceContainer,MapWithPointers,DeeplyNestedMap,NamedMapContainer,MapSlicePointerContainer
|
||||
//go:generate go run tailscale.com/cmd/cloner -clonefunc=true -type SliceContainer,InterfaceContainer,MapWithPointers,DeeplyNestedMap,NamedMapContainer,MapSlicePointerContainer,MapWithNamedSliceValues
|
||||
|
||||
// Package clonerex is an example package for the cloner tool.
|
||||
package clonerex
|
||||
@ -72,3 +72,12 @@ type DeeplyNestedMap struct {
|
||||
ThreeLevels map[string]map[string]map[string]int
|
||||
FourLevels map[string]map[string]map[string]map[string]*SliceContainer
|
||||
}
|
||||
|
||||
// MapWithNamedSliceValues has a map with a named slice type for values. This
|
||||
// tests that the generator treats these values like any other slice and not a
|
||||
// struct.
|
||||
type MapWithNamedSliceValues struct {
|
||||
M map[string]NamedSlice
|
||||
}
|
||||
|
||||
type NamedSlice []string
|
||||
|
||||
@ -209,9 +209,31 @@ func (src *MapSlicePointerContainer) Clone() *MapSlicePointerContainer {
|
||||
Routes map[string][]*SliceContainer
|
||||
}{})
|
||||
|
||||
// Clone makes a deep copy of MapWithNamedSliceValues.
|
||||
// The result aliases no memory with the original.
|
||||
func (src *MapWithNamedSliceValues) Clone() *MapWithNamedSliceValues {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
dst := new(MapWithNamedSliceValues)
|
||||
*dst = *src
|
||||
if dst.M != nil {
|
||||
dst.M = map[string]NamedSlice{}
|
||||
for k := range src.M {
|
||||
dst.M[k] = append([]string{}, src.M[k]...)
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
||||
var _MapWithNamedSliceValuesCloneNeedsRegeneration = MapWithNamedSliceValues(struct {
|
||||
M map[string]NamedSlice
|
||||
}{})
|
||||
|
||||
// Clone duplicates src into dst and reports whether it succeeded.
|
||||
// To succeed, <src, dst> must be of types <*T, *T> or <*T, **T>,
|
||||
// where T is one of SliceContainer,InterfaceContainer,MapWithPointers,DeeplyNestedMap,NamedMapContainer,MapSlicePointerContainer.
|
||||
// where T is one of SliceContainer,InterfaceContainer,MapWithPointers,DeeplyNestedMap,NamedMapContainer,MapSlicePointerContainer,MapWithNamedSliceValues.
|
||||
func Clone(dst, src any) bool {
|
||||
switch src := src.(type) {
|
||||
case *SliceContainer:
|
||||
@ -268,6 +290,15 @@ func Clone(dst, src any) bool {
|
||||
*dst = src.Clone()
|
||||
return true
|
||||
}
|
||||
case *MapWithNamedSliceValues:
|
||||
switch dst := dst.(type) {
|
||||
case *MapWithNamedSliceValues:
|
||||
*dst = *src.Clone()
|
||||
return true
|
||||
case **MapWithNamedSliceValues:
|
||||
*dst = src.Clone()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user