-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
provide generic API in github.com/huandu/go-clone/generic
- Loading branch information
Showing
9 changed files
with
248 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Generic `go-clone` API | ||
|
||
[![Go](https://github.com/huandu/go-clone/workflows/Go/badge.svg)](https://github.com/huandu/go-clone/actions) | ||
[![Go Doc](https://godoc.org/github.com/huandu/go-clone/generic?status.svg)](https://pkg.go.dev/github.com/huandu/go-clone/generic) | ||
|
||
This package is a set of generic API for `go-clone`. All methods are simple proxies. It requires `go1.18` or later to build this package. | ||
|
||
Please read document in [the main project](../README.md) for more information. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Copyright 2022 Huan Du. All rights reserved. | ||
// Licensed under the MIT license that can be found in the LICENSE file. | ||
|
||
// Package clone provides functions to deep clone any Go data. | ||
// It also provides a wrapper to protect a pointer from any unexpected mutation. | ||
// | ||
// This package is only a proxy to original go-clone package with generic support. | ||
// To minimize the maintenace cost, there is no doc in this package. | ||
// Please read the document in https://pkg.go.dev/github.com/huandu/go-clone instead. | ||
package clone | ||
|
||
import ( | ||
"reflect" | ||
|
||
"github.com/huandu/go-clone" | ||
) | ||
|
||
type Func = clone.Func | ||
|
||
func Clone[T any](t T) T { | ||
return clone.Clone(t).(T) | ||
} | ||
|
||
func Slowly[T any](t T) T { | ||
return clone.Slowly(t).(T) | ||
} | ||
|
||
func Wrap[T any](t T) T { | ||
return clone.Wrap(t).(T) | ||
} | ||
|
||
func Unwrap[T any](t T) T { | ||
return clone.Unwrap(t).(T) | ||
} | ||
|
||
func Undo[T any](t T) { | ||
clone.Undo(t) | ||
} | ||
|
||
func MarkAsOpaquePointer(t reflect.Type) { | ||
clone.MarkAsOpaquePointer(t) | ||
} | ||
|
||
func MarkAsScalar(t reflect.Type) { | ||
clone.MarkAsScalar(t) | ||
} | ||
|
||
func SetCustomFunc(t reflect.Type, fn Func) { | ||
clone.SetCustomFunc(t, fn) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// Copyright 2022 Huan Du. All rights reserved. | ||
// Licensed under the MIT license that can be found in the LICENSE file. | ||
|
||
package clone | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/huandu/go-assert" | ||
) | ||
|
||
type MyType struct { | ||
Foo int | ||
bar string | ||
} | ||
|
||
func TestGenericAPI(t *testing.T) { | ||
a := assert.New(t) | ||
original := &MyType{ | ||
Foo: 123, | ||
bar: "player", | ||
} | ||
|
||
var v *MyType = Clone(original) | ||
a.Equal(v, original) | ||
|
||
v = Slowly(original) | ||
a.Equal(v, original) | ||
|
||
v = Wrap(original) | ||
a.Equal(v, original) | ||
a.Assert(Unwrap(v) == original) | ||
|
||
v.Foo = 777 | ||
a.Equal(Unwrap(v).Foo, original.Foo) | ||
|
||
Undo(v) | ||
a.Equal(v, original) | ||
} | ||
|
||
type MyPointer struct { | ||
Foo *int | ||
P *MyPointer | ||
} | ||
|
||
func TestMarkAsAPI(t *testing.T) { | ||
a := assert.New(t) | ||
MarkAsScalar(reflect.TypeOf(MyPointer{})) | ||
MarkAsOpaquePointer(reflect.TypeOf(&MyPointer{})) | ||
|
||
n := 0 | ||
orignal := MyPointer{ | ||
Foo: &n, | ||
} | ||
orignal.P = &orignal | ||
|
||
v := Clone(orignal) | ||
a.Assert(v.Foo == orignal.Foo) | ||
a.Assert(v.P == &orignal) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
module github.com/huandu/go-clone/generic | ||
|
||
go 1.18 | ||
|
||
require ( | ||
github.com/huandu/go-assert v1.1.5 | ||
github.com/huandu/go-clone v1.4.0 | ||
) | ||
|
||
require github.com/davecgh/go-spew v1.1.1 // indirect |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= | ||
github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= | ||
github.com/huandu/go-clone v1.4.0 h1:NlnghW4lsmMoz+3N4yb4Ouff86ArRYPo/1aCsqQKKF4= | ||
github.com/huandu/go-clone v1.4.0/go.mod h1:ReGivhG6op3GYr+UY3lS6mxjKp7MIGTknuU5TbTVaXE= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright 2022 Huan Du. All rights reserved. | ||
// Licensed under the MIT license that can be found in the LICENSE file. | ||
|
||
package clone | ||
|
||
import ( | ||
"reflect" | ||
"sync/atomic" | ||
) | ||
|
||
// Record the count of cloning atomic.Pointer[T] for test purpose only. | ||
var registerAtomicPointerCalled int32 | ||
|
||
// RegisterAtomicPointer registers a custom clone function for atomic.Pointer[T]. | ||
func RegisterAtomicPointer[T any]() { | ||
SetCustomFunc(reflect.TypeOf(atomic.Pointer[T]{}), func(old, new reflect.Value) { | ||
if !old.CanAddr() { | ||
return | ||
} | ||
|
||
// Clone value inside atomic.Pointer[T]. | ||
oldValue := old.Addr().Interface().(*atomic.Pointer[T]) | ||
newValue := new.Addr().Interface().(*atomic.Pointer[T]) | ||
v := oldValue.Load() | ||
newValue.Store(v) | ||
|
||
atomic.AddInt32(®isterAtomicPointerCalled, 1) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// Copyright 2022 Huan Du. All rights reserved. | ||
// Licensed under the MIT license that can be found in the LICENSE file. | ||
|
||
package clone | ||
|
||
import ( | ||
"sync/atomic" | ||
"testing" | ||
|
||
"github.com/huandu/go-assert" | ||
) | ||
|
||
type RegisteredPayload struct { | ||
T string | ||
} | ||
|
||
type UnregisteredPayload struct { | ||
T string | ||
} | ||
|
||
type Pointers struct { | ||
P1 atomic.Pointer[RegisteredPayload] | ||
P2 atomic.Pointer[UnregisteredPayload] | ||
} | ||
|
||
func TestRegisterAtomicPointer(t *testing.T) { | ||
a := assert.New(t) | ||
s := &Pointers{} | ||
stackPointerCannotBeCloned := atomic.Pointer[RegisteredPayload]{} | ||
|
||
// Register atomic.Pointer[RegisteredPayload] only. | ||
RegisterAtomicPointer[RegisteredPayload]() | ||
|
||
prev := registerAtomicPointerCalled | ||
Clone(s) | ||
Clone(stackPointerCannotBeCloned) | ||
a.Equal(registerAtomicPointerCalled, prev+1) | ||
} |