Skip to content
This repository was archived by the owner on Mar 16, 2025. It is now read-only.

Commit 7bea6fb

Browse files
committed
add support for custom deepcopy logic
1 parent e2d0344 commit 7bea6fb

2 files changed

Lines changed: 73 additions & 3 deletions

File tree

pkg/deepcopy/deepcopy.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ func MustClone[T any](val T) T {
3030
return cloned
3131
}
3232

33+
type Copier interface {
34+
DeepCopy() (any, error)
35+
}
36+
3337
func clone(val any) (any, error) {
3438
switch asserted := val.(type) {
3539
// Go native types
@@ -66,6 +70,10 @@ func clone(val any) (any, error) {
6670
case ast.String:
6771
return asserted, nil
6872

73+
// custom logic
74+
case Copier:
75+
return asserted.DeepCopy()
76+
6977
default:
7078
return nil, fmt.Errorf("cannot deep-copy %T", val)
7179
}

pkg/deepcopy/deepcopy_test.go

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,40 @@ import (
88
"github.com/google/go-cmp/cmp"
99
)
1010

11+
type customCopier struct {
12+
Value any
13+
}
14+
15+
var _ Copier = customCopier{}
16+
17+
func (c customCopier) DeepCopy() (any, error) {
18+
copied, err := Clone(c.Value)
19+
if err != nil {
20+
return nil, err
21+
}
22+
23+
return customCopier{
24+
Value: copied,
25+
}, nil
26+
}
27+
28+
type customPtrCopier struct {
29+
Value any
30+
}
31+
32+
var _ Copier = &customPtrCopier{}
33+
34+
func (c *customPtrCopier) DeepCopy() (any, error) {
35+
copied, err := Clone(c.Value)
36+
if err != nil {
37+
return nil, err
38+
}
39+
40+
return &customPtrCopier{
41+
Value: copied,
42+
}, nil
43+
}
44+
1145
func TestCloneScalars(t *testing.T) {
1246
testcases := []struct {
1347
input any
@@ -75,7 +109,7 @@ func TestCloneScalars(t *testing.T) {
75109
}
76110

77111
if !cmp.Equal(cloned, testcase.expected) {
78-
t.Fatalf("Unpected result:\n\n%s\n", renderDiff(testcase.expected, cloned))
112+
t.Fatalf("Unexpected result:\n\n%s\n", renderDiff(testcase.expected, cloned))
79113
}
80114

81115
if &cloned == &testcase.input {
@@ -120,7 +154,7 @@ func TestCloneMapDeep(t *testing.T) {
120154
}
121155

122156
if !cmp.Equal(cloned, input) {
123-
t.Fatalf("Unpected result:\n\n%s\n", renderDiff(input, cloned))
157+
t.Fatalf("Unexpected result:\n\n%s\n", renderDiff(input, cloned))
124158
}
125159

126160
helloList := input["hello"].([]any)
@@ -164,7 +198,7 @@ func TestCloneSliceDeep(t *testing.T) {
164198
}
165199

166200
if !cmp.Equal(cloned, input) {
167-
t.Fatalf("Unpected result:\n\n%s\n", renderDiff(input, cloned))
201+
t.Fatalf("Unexpected result:\n\n%s\n", renderDiff(input, cloned))
168202
}
169203

170204
helloObj := input[3].(map[string]any)
@@ -175,6 +209,34 @@ func TestCloneSliceDeep(t *testing.T) {
175209
}
176210
}
177211

212+
func TestCustomCopier(t *testing.T) {
213+
data := map[string]any{"foo": "bar"}
214+
cc := customCopier{Value: data}
215+
216+
cloned, err := Clone(cc)
217+
if err != nil {
218+
t.Fatalf("Failed to clone: %v", err)
219+
}
220+
221+
if !cmp.Equal(cc, cloned) {
222+
t.Fatalf("Unexpected result:\n\n%s\n", renderDiff(cc, cloned))
223+
}
224+
}
225+
226+
func TestCustomPtrCopier(t *testing.T) {
227+
data := map[string]any{"foo": "bar"}
228+
cc := &customPtrCopier{Value: data}
229+
230+
cloned, err := Clone(cc)
231+
if err != nil {
232+
t.Fatalf("Failed to clone: %v", err)
233+
}
234+
235+
if !cmp.Equal(cc, cloned) {
236+
t.Fatalf("Unexpected result:\n\n%s\n", renderDiff(cc, cloned))
237+
}
238+
}
239+
178240
func renderDiff(expected any, actual any) string {
179241
var builder strings.Builder
180242

0 commit comments

Comments
 (0)