Skip to content

Commit

Permalink
Refactor: remove redundant code and update README
Browse files Browse the repository at this point in the history
  • Loading branch information
tiendc committed Sep 22, 2024
1 parent 979a151 commit c2c759b
Show file tree
Hide file tree
Showing 7 changed files with 32 additions and 59 deletions.
45 changes: 19 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ go get github.com/tiendc/go-deepcopy
- [Copy between struct fields with different names](#copy-between-struct-fields-with-different-names)
- [Ignore copying struct fields](#ignore-copying-struct-fields)
- [Copy between struct fields and methods](#copy-between-struct-fields-and-methods)
- [Copy from source having embedded structs](#copy-from-source-having-embedded-structs)
- [Copy between inherited fields from embedded structs](#copy-between-inherited-fields-from-embedded-structs)
- [Copy between unexported struct fields](#copy-between-unexported-struct-fields)
- [Configure copying behavior](#configure-copying-behavior)

Expand Down Expand Up @@ -124,6 +124,8 @@ go get github.com/tiendc/go-deepcopy

### Copy between struct fields and methods

- **Note**: If a copying method is defined in a struct, it will have higher priority than matching field.

[Playground 1](https://go.dev/play/p/zb2NU32G2mG) /
[Playground 2](https://go.dev/play/p/C3FpFwzoPFm)

Expand Down Expand Up @@ -159,35 +161,26 @@ func (d *D) CopyX(i int) error {
// {x:11 U:22}
```

### Copy from source having embedded structs
### Copy between inherited fields from embedded structs

[Playground 1](https://go.dev/play/p/e7nvdqqZ6MF) /
[Playground 2](https://go.dev/play/p/UF8ppU5kD7v) /
[Playground 3](https://go.dev/play/p/YrCwKkHvyIe)
- This is default behaviour from version 1.0, for lower versions, you can use custom copying function
to achieve the same result.

```go
// Source struct has embedded struct
type SBase struct {
St string
}
type S struct {
SBase
I int
}
// but destination struct doesn't
type D struct {
I int
St string
}
type SBase struct {
St string
}
// Source struct has embedded struct
type S struct {
SBase
I int
}
// but destination struct doesn't
type D struct {
I int
St string
}

// You want to copy `S.SBase.St` to `D.St`
func (d *D) CopySBase(sb SBase) error {
// you can even call deepcopy.Copy(d, sb) if SBase has many fields
d.St = sb.St
return nil
}
```
```go
src := []S{{I: 1, SBase: SBase{"abc"}}, {I: 11, SBase: SBase{"xyz"}}}
var dst []D
_ = deepcopy.Copy(&dst, src)
Expand Down
4 changes: 2 additions & 2 deletions base_copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ type ptr2ValueCopier struct {
func (c *ptr2ValueCopier) Copy(dst, src reflect.Value) error {
src = src.Elem()
if !src.IsValid() {
dst.Set(reflect.Zero(dst.Type())) // TODO: Go1.18 has no SetZero
dst.Set(reflect.Zero(dst.Type())) // NOTE: Go1.18 has no SetZero
return nil
}
return c.copier.Copy(dst, src)
Expand All @@ -69,7 +69,7 @@ type ptr2PtrCopier struct {
func (c *ptr2PtrCopier) Copy(dst, src reflect.Value) error {
src = src.Elem()
if !src.IsValid() {
dst.Set(reflect.Zero(dst.Type())) // TODO: Go1.18 has no SetZero
dst.Set(reflect.Zero(dst.Type())) // NOTE: Go1.18 has no SetZero
return nil
}
if dst.IsNil() {
Expand Down
5 changes: 3 additions & 2 deletions build_copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ func defaultContext() *Context {
}

// buildCopier build copier for handling copy from `srcType` to `dstType`
// nolint: gocognit, gocyclo
//
//nolint:gocognit,gocyclo
func buildCopier(ctx *Context, dstType, srcType reflect.Type) (copier, error) {
dstKind, srcKind := dstType.Kind(), srcType.Kind()
if dstKind == reflect.Interface {
Expand All @@ -106,7 +107,7 @@ func buildCopier(ctx *Context, dstType, srcType reflect.Type) (copier, error) {
return &fromIfaceCopier{ctx: ctx}, nil
}

// nolint: nestif
//nolint:nestif
if srcKind == reflect.Pointer {
if dstKind == reflect.Pointer { // ptr -> ptr
copier := &ptr2PtrCopier{ctx: ctx}
Expand Down
2 changes: 1 addition & 1 deletion deepcopy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ var (
M1: map[int]string{1: "11", 2: "22", 3: "33"},
M2: nil,
M3: map[int]int{7: 77, 8: 88, 9: 99},
// nolint: gofmt
//nolint:gofmt
M4: map[[3]int]*srcStruct2{
[3]int{1, 1, 1}: &srcStructA,
[3]int{2, 2, 2}: &srcStructB,
Expand Down
4 changes: 2 additions & 2 deletions iface_copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func (c *fromIfaceCopier) Copy(dst, src reflect.Value) error {
for src.Kind() == reflect.Interface {
src = src.Elem()
if !src.IsValid() {
dst.Set(reflect.Zero(dst.Type())) // TODO: Go1.18 has no SetZero
dst.Set(reflect.Zero(dst.Type())) // NOTE: Go1.18 has no SetZero

Check warning on line 17 in iface_copier.go

View check run for this annotation

Codecov / codecov/patch

iface_copier.go#L17

Added line #L17 was not covered by tests
return nil
}
}
Expand All @@ -35,7 +35,7 @@ func (c *toIfaceCopier) Copy(dst, src reflect.Value) error {
for src.Kind() == reflect.Interface {
src = src.Elem()
if !src.IsValid() {
dst.Set(reflect.Zero(dst.Type())) // TODO: Go1.18 has no SetZero
dst.Set(reflect.Zero(dst.Type())) // NOTE: Go1.18 has no SetZero
return nil
}
}
Expand Down
2 changes: 1 addition & 1 deletion map_copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type mapCopier struct {
// Copy implementation of Copy function for map copier
func (c *mapCopier) Copy(dst, src reflect.Value) (err error) {
if src.IsNil() {
dst.Set(reflect.Zero(dst.Type())) // TODO: Go1.18 has no SetZero
dst.Set(reflect.Zero(dst.Type())) // NOTE: Go1.18 has no SetZero
return nil
}
if dst.IsNil() {
Expand Down
29 changes: 4 additions & 25 deletions slice_copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func (c *sliceCopier) Copy(dst, src reflect.Value) error {
if dst.Kind() == reflect.Slice { // Slice/Array -> Slice
// `src` is nil slice, set `dst` nil
if src.Kind() == reflect.Slice && src.IsNil() {
dst.Set(reflect.Zero(dst.Type())) // TODO: Go1.18 has no SetZero
dst.Set(reflect.Zero(dst.Type())) // NOTE: Go1.18 has no SetZero
return nil
}
newSlice := reflect.MakeSlice(dst.Type(), srcLen, srcLen)
Expand All @@ -42,7 +42,7 @@ func (c *sliceCopier) Copy(dst, src reflect.Value) error {
}
for ; i < dstLen; i++ {
item := dst.Index(i)
item.Set(reflect.Zero(item.Type())) // TODO: Go1.18 has no SetZero
item.Set(reflect.Zero(item.Type())) // NOTE: Go1.18 has no SetZero
}
return nil
}
Expand All @@ -54,11 +54,11 @@ func (c *sliceCopier) init(dstType, srcType reflect.Type) (err error) {
// OPTIMIZATION: buildCopier() can handle this nicely, but it will add another wrapping layer
if simpleKindMask&(1<<srcKind) > 0 {
if srcType == dstType {
c.itemCopier = &sliceItemDirectCopier{}
c.itemCopier = &directCopier{}
return nil
}
if srcType.ConvertibleTo(dstType) {
c.itemCopier = &sliceItemConvCopier{}
c.itemCopier = &convCopier{}
return nil
}
}
Expand All @@ -77,24 +77,3 @@ func (c *sliceCopier) init(dstType, srcType reflect.Type) (err error) {
c.itemCopier, err = buildCopier(c.ctx, dstType, srcType)
return
}

// sliceItemDirectCopier copier that copies from a slice item to a destination value directly
type sliceItemDirectCopier struct {
}

// Copy implementation of Copy function for slice item copier direct
func (c *sliceItemDirectCopier) Copy(dst, src reflect.Value) error {
dst.Set(src)
return nil
}

// sliceItemConvCopier copier that copies from a slice item to a destination value
// with converting `src` value to `dst` type
type sliceItemConvCopier struct {
}

// Copy implementation of Copy function for slice item copier with-conversion
func (c *sliceItemConvCopier) Copy(dst, src reflect.Value) error {
dst.Set(src.Convert(dst.Type()))
return nil
}

0 comments on commit c2c759b

Please sign in to comment.