mirror of
https://github.com/tailscale/tailscale.git
synced 2026-05-05 20:26:47 +02:00
The cloner and viewer code generators didn't handle named types
with basic underlying types (map/slice) that have their own Clone
or View methods. For example, a type like:
type Map map[string]any
func (m Map) Clone() Map { ... }
func (m Map) View() MapView { ... }
When used as a struct field, the cloner would descend into the
underlying map[string]any and fail because it can't clone the any
(interface{}) value type. Similarly, the viewer would try to create
a MapFnOf view and fail.
Fix the cloner to check for a Clone method on the named type
before falling through to the underlying type handling.
Fix the viewer to check for a View method on named map/slice types,
so the type author can provide a purpose-built safe view that
doesn't leak raw any values. Named map/slice types without a View
method fall through to normal handling, which correctly rejects
types like map[string]any as unsupported.
Updates tailscale/corp#39502 (needed by tailscale/corp#39594)
Change-Id: Iaef0192a221e02b4b8e409c99ef8398090327744
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
232 lines
5.8 KiB
Go
232 lines
5.8 KiB
Go
// Copyright (c) Tailscale Inc & contributors
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
// Code generated by tailscale.com/cmd/cloner; DO NOT EDIT.
|
|
|
|
package clonerex
|
|
|
|
import (
|
|
"maps"
|
|
)
|
|
|
|
// Clone makes a deep copy of SliceContainer.
|
|
// The result aliases no memory with the original.
|
|
func (src *SliceContainer) Clone() *SliceContainer {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dst := new(SliceContainer)
|
|
*dst = *src
|
|
if src.Slice != nil {
|
|
dst.Slice = make([]*int, len(src.Slice))
|
|
for i := range dst.Slice {
|
|
if src.Slice[i] == nil {
|
|
dst.Slice[i] = nil
|
|
} else {
|
|
dst.Slice[i] = new(*src.Slice[i])
|
|
}
|
|
}
|
|
}
|
|
return dst
|
|
}
|
|
|
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
|
var _SliceContainerCloneNeedsRegeneration = SliceContainer(struct {
|
|
Slice []*int
|
|
}{})
|
|
|
|
// Clone makes a deep copy of InterfaceContainer.
|
|
// The result aliases no memory with the original.
|
|
func (src *InterfaceContainer) Clone() *InterfaceContainer {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dst := new(InterfaceContainer)
|
|
*dst = *src
|
|
if src.Interface != nil {
|
|
dst.Interface = src.Interface.Clone()
|
|
}
|
|
return dst
|
|
}
|
|
|
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
|
var _InterfaceContainerCloneNeedsRegeneration = InterfaceContainer(struct {
|
|
Interface Cloneable
|
|
}{})
|
|
|
|
// Clone makes a deep copy of MapWithPointers.
|
|
// The result aliases no memory with the original.
|
|
func (src *MapWithPointers) Clone() *MapWithPointers {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dst := new(MapWithPointers)
|
|
*dst = *src
|
|
if dst.Nested != nil {
|
|
dst.Nested = map[string]*int{}
|
|
for k, v := range src.Nested {
|
|
if v == nil {
|
|
dst.Nested[k] = nil
|
|
} else {
|
|
dst.Nested[k] = new(*v)
|
|
}
|
|
}
|
|
}
|
|
if dst.WithCloneMethod != nil {
|
|
dst.WithCloneMethod = map[string]*SliceContainer{}
|
|
for k, v := range src.WithCloneMethod {
|
|
if v == nil {
|
|
dst.WithCloneMethod[k] = nil
|
|
} else {
|
|
dst.WithCloneMethod[k] = v.Clone()
|
|
}
|
|
}
|
|
}
|
|
if dst.CloneInterface != nil {
|
|
dst.CloneInterface = map[string]Cloneable{}
|
|
for k, v := range src.CloneInterface {
|
|
dst.CloneInterface[k] = v.Clone()
|
|
}
|
|
}
|
|
return dst
|
|
}
|
|
|
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
|
var _MapWithPointersCloneNeedsRegeneration = MapWithPointers(struct {
|
|
Nested map[string]*int
|
|
WithCloneMethod map[string]*SliceContainer
|
|
CloneInterface map[string]Cloneable
|
|
}{})
|
|
|
|
// Clone makes a deep copy of DeeplyNestedMap.
|
|
// The result aliases no memory with the original.
|
|
func (src *DeeplyNestedMap) Clone() *DeeplyNestedMap {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dst := new(DeeplyNestedMap)
|
|
*dst = *src
|
|
if dst.ThreeLevels != nil {
|
|
dst.ThreeLevels = map[string]map[string]map[string]int{}
|
|
for k, v := range src.ThreeLevels {
|
|
if v == nil {
|
|
dst.ThreeLevels[k] = nil
|
|
continue
|
|
}
|
|
dst.ThreeLevels[k] = map[string]map[string]int{}
|
|
for k2, v2 := range v {
|
|
dst.ThreeLevels[k][k2] = maps.Clone(v2)
|
|
}
|
|
}
|
|
}
|
|
if dst.FourLevels != nil {
|
|
dst.FourLevels = map[string]map[string]map[string]map[string]*SliceContainer{}
|
|
for k, v := range src.FourLevels {
|
|
if v == nil {
|
|
dst.FourLevels[k] = nil
|
|
continue
|
|
}
|
|
dst.FourLevels[k] = map[string]map[string]map[string]*SliceContainer{}
|
|
for k2, v2 := range v {
|
|
if v2 == nil {
|
|
dst.FourLevels[k][k2] = nil
|
|
continue
|
|
}
|
|
dst.FourLevels[k][k2] = map[string]map[string]*SliceContainer{}
|
|
for k3, v3 := range v2 {
|
|
if v3 == nil {
|
|
dst.FourLevels[k][k2][k3] = nil
|
|
continue
|
|
}
|
|
dst.FourLevels[k][k2][k3] = map[string]*SliceContainer{}
|
|
for k4, v4 := range v3 {
|
|
if v4 == nil {
|
|
dst.FourLevels[k][k2][k3][k4] = nil
|
|
} else {
|
|
dst.FourLevels[k][k2][k3][k4] = v4.Clone()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return dst
|
|
}
|
|
|
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
|
var _DeeplyNestedMapCloneNeedsRegeneration = DeeplyNestedMap(struct {
|
|
ThreeLevels map[string]map[string]map[string]int
|
|
FourLevels map[string]map[string]map[string]map[string]*SliceContainer
|
|
}{})
|
|
|
|
// Clone makes a deep copy of NamedMapContainer.
|
|
// The result aliases no memory with the original.
|
|
func (src *NamedMapContainer) Clone() *NamedMapContainer {
|
|
if src == nil {
|
|
return nil
|
|
}
|
|
dst := new(NamedMapContainer)
|
|
*dst = *src
|
|
dst.Attrs = src.Attrs.Clone()
|
|
return dst
|
|
}
|
|
|
|
// A compilation failure here means this code must be regenerated, with the command at the top of this file.
|
|
var _NamedMapContainerCloneNeedsRegeneration = NamedMapContainer(struct {
|
|
Attrs NamedMap
|
|
}{})
|
|
|
|
// 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.
|
|
func Clone(dst, src any) bool {
|
|
switch src := src.(type) {
|
|
case *SliceContainer:
|
|
switch dst := dst.(type) {
|
|
case *SliceContainer:
|
|
*dst = *src.Clone()
|
|
return true
|
|
case **SliceContainer:
|
|
*dst = src.Clone()
|
|
return true
|
|
}
|
|
case *InterfaceContainer:
|
|
switch dst := dst.(type) {
|
|
case *InterfaceContainer:
|
|
*dst = *src.Clone()
|
|
return true
|
|
case **InterfaceContainer:
|
|
*dst = src.Clone()
|
|
return true
|
|
}
|
|
case *MapWithPointers:
|
|
switch dst := dst.(type) {
|
|
case *MapWithPointers:
|
|
*dst = *src.Clone()
|
|
return true
|
|
case **MapWithPointers:
|
|
*dst = src.Clone()
|
|
return true
|
|
}
|
|
case *DeeplyNestedMap:
|
|
switch dst := dst.(type) {
|
|
case *DeeplyNestedMap:
|
|
*dst = *src.Clone()
|
|
return true
|
|
case **DeeplyNestedMap:
|
|
*dst = src.Clone()
|
|
return true
|
|
}
|
|
case *NamedMapContainer:
|
|
switch dst := dst.(type) {
|
|
case *NamedMapContainer:
|
|
*dst = *src.Clone()
|
|
return true
|
|
case **NamedMapContainer:
|
|
*dst = src.Clone()
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|