Skip to content

Commit

Permalink
Add go docs for functions and types (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
tiendc authored Jul 26, 2024
1 parent f91fb04 commit fd7c970
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 7 deletions.
11 changes: 11 additions & 0 deletions base_copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,27 @@ import (
"reflect"
)

// copier base interface defines Copy function
type copier interface {
Copy(dst, src reflect.Value) error
}

// nopCopier no-op copier
type nopCopier struct {
}

// Copy implementation of Copy function for no-op copier
func (c *nopCopier) Copy(dst, src reflect.Value) error {
return nil
}

// value2PtrCopier data structure of copier that copies from a value to a pointer
type value2PtrCopier struct {
ctx *Context
copier copier
}

// Copy implementation of Copy function for value-to-pointer copier
func (c *value2PtrCopier) Copy(dst, src reflect.Value) error {
if dst.IsNil() {
dst.Set(reflect.New(dst.Type().Elem()))
Expand All @@ -33,11 +38,13 @@ func (c *value2PtrCopier) init(dstType, srcType reflect.Type) (err error) {
return
}

// ptr2ValueCopier data structure of copier that copies from a pointer to a value
type ptr2ValueCopier struct {
ctx *Context
copier copier
}

// Copy implementation of Copy function for pointer-to-value copier
func (c *ptr2ValueCopier) Copy(dst, src reflect.Value) error {
src = src.Elem()
if !src.IsValid() {
Expand All @@ -52,11 +59,13 @@ func (c *ptr2ValueCopier) init(dstType, srcType reflect.Type) (err error) {
return
}

// ptr2PtrCopier data structure of copier that copies from a pointer to a pointer
type ptr2PtrCopier struct {
ctx *Context
copier copier
}

// Copy implementation of Copy function for pointer-to-pointer copier
func (c *ptr2PtrCopier) Copy(dst, src reflect.Value) error {
src = src.Elem()
if !src.IsValid() {
Expand All @@ -75,6 +84,7 @@ func (c *ptr2PtrCopier) init(dstType, srcType reflect.Type) (err error) {
return
}

// directCopier copier that does copying by assigning `src` value to `dst` directly
type directCopier struct {
}

Expand All @@ -83,6 +93,7 @@ func (c *directCopier) Copy(dst, src reflect.Value) error {
return nil
}

// convCopier copier that does copying with converting `src` value to `dst` type
type convCopier struct {
}

Expand Down
11 changes: 9 additions & 2 deletions build_copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"sync"
)

// cacheKey key data structure of cached copiers
type cacheKey struct {
dstType reflect.Type
srcType reflect.Type
Expand Down Expand Up @@ -45,11 +46,15 @@ var (
)

const (
flagCopyBetweenPtrAndValue = 1
// flagCopyBetweenPtrAndValue indicates copying will be performed between `pointers` and `values`
flagCopyBetweenPtrAndValue = 1
// flagCopyBetweenStructFieldAndMethod indicates copying will be performed between `struct fields` and `functions`
flagCopyBetweenStructFieldAndMethod = 2
flagIgnoreNonCopyableTypes = 3
// flagIgnoreNonCopyableTypes indicates copying will skip copying non-copyable types without raising errors
flagIgnoreNonCopyableTypes = 3
)

// prepare prepares context for copiers
func (ctx *Context) prepare() {
if ctx.UseGlobalCache {
ctx.copierCacheMap = copierCacheMap
Expand All @@ -72,6 +77,7 @@ func (ctx *Context) prepare() {
}
}

// createCacheKey creates and returns key for caching a copier
func (ctx *Context) createCacheKey(dstType, srcType reflect.Type) *cacheKey {
return &cacheKey{
dstType: dstType,
Expand All @@ -80,6 +86,7 @@ func (ctx *Context) createCacheKey(dstType, srcType reflect.Type) *cacheKey {
}
}

// defaultContext creates a default context
func defaultContext() *Context {
return &Context{
CopyBetweenPtrAndValue: true,
Expand Down
14 changes: 13 additions & 1 deletion deepcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ import (
)

const (
// DefaultTagName default tag name for the program to parse input struct tags
// to build copier configuration.
DefaultTagName = "copy"
)

// Context copier context
type Context struct {
// CopyBetweenPtrAndValue allow or not copying between pointers and values (default is `true`)
CopyBetweenPtrAndValue bool
Expand All @@ -29,30 +32,39 @@ type Context struct {
flags uint8
}

// Option configuration option function provided as extra arguments of copying function
type Option func(ctx *Context)

// CopyBetweenPtrAndValue config function for setting flag `CopyBetweenPtrAndValue`
func CopyBetweenPtrAndValue(flag bool) Option {
return func(ctx *Context) {
ctx.CopyBetweenPtrAndValue = flag
}
}

// CopyBetweenStructFieldAndMethod config function for setting flag `CopyBetweenStructFieldAndMethod`
func CopyBetweenStructFieldAndMethod(flag bool) Option {
return func(ctx *Context) {
ctx.CopyBetweenStructFieldAndMethod = flag
}
}

// IgnoreNonCopyableTypes config function for setting flag `IgnoreNonCopyableTypes`
func IgnoreNonCopyableTypes(flag bool) Option {
return func(ctx *Context) {
ctx.IgnoreNonCopyableTypes = flag
}
}

// UseGlobalCache config function for setting flag `UseGlobalCache`
func UseGlobalCache(flag bool) Option {
return func(ctx *Context) {
ctx.UseGlobalCache = flag
}
}

// Copy performs deep copy from `src` to `dst`.
//
// `dst` must be a pointer to the output var, `src` can be either value or pointer.
// In case you want to copy unexported struct fields within `src`, `src` must be a pointer.
func Copy(dst, src any, options ...Option) (err error) {
Expand Down Expand Up @@ -98,7 +110,7 @@ func Copy(dst, src any, options ...Option) (err error) {
return cp.Copy(dstVal, srcVal)
}

// ClearCache clears global cache
// ClearCache clears global cache of previously used copiers
func ClearCache() {
mu.Lock()
copierCacheMap = map[cacheKey]copier{}
Expand Down
16 changes: 12 additions & 4 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@ import (
"errors"
)

// Errors may be returned from Copy function
var (
ErrTypeInvalid = errors.New("ErrTypeInvalid")
ErrTypeNonCopyable = errors.New("ErrTypeNonCopyable")
ErrValueInvalid = errors.New("ErrValueInvalid")
ErrValueUnaddressable = errors.New("ErrValueUnaddressable")
// ErrTypeInvalid returned when type of input var does not meet the requirement
ErrTypeInvalid = errors.New("ErrTypeInvalid")
// ErrTypeNonCopyable returned when the function can not perform copying between types
ErrTypeNonCopyable = errors.New("ErrTypeNonCopyable")
// ErrValueInvalid returned when input value does not meet the requirement
ErrValueInvalid = errors.New("ErrValueInvalid")
// ErrValueUnaddressable returned when value is `unaddressable` which is required
// in some situations such as when accessing an unexported struct field.
ErrValueUnaddressable = errors.New("ErrValueUnaddressable")
// ErrFieldRequireCopying returned when a field is required to be copied
// but no copying is done for it.
ErrFieldRequireCopying = errors.New("ErrFieldRequireCopying")
)
4 changes: 4 additions & 0 deletions iface_copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import (
"reflect"
)

// fromIfaceCopier data structure of copier that copies from an interface
type fromIfaceCopier struct {
ctx *Context
}

// Copy implementation of Copy function for from-iface copier
func (c *fromIfaceCopier) Copy(dst, src reflect.Value) error {
for src.Kind() == reflect.Interface {
src = src.Elem()
Expand All @@ -23,10 +25,12 @@ func (c *fromIfaceCopier) Copy(dst, src reflect.Value) error {
return cp.Copy(dst, src)
}

// toIfaceCopier data structure of copier that copies to an interface
type toIfaceCopier struct {
ctx *Context
}

// Copy implementation of Copy function for to-iface copier
func (c *toIfaceCopier) Copy(dst, src reflect.Value) error {
for src.Kind() == reflect.Interface {
src = src.Elem()
Expand Down
4 changes: 4 additions & 0 deletions map_copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import (
"reflect"
)

// mapCopier data structure of copier that copies from a `map`
type mapCopier struct {
ctx *Context
keyCopier *mapItemCopier
valueCopier *mapItemCopier
}

// 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
Expand Down Expand Up @@ -81,11 +83,13 @@ func (c *mapCopier) init(dstType, srcType reflect.Type) error {
return nil
}

// mapItemCopier data structure of copier that copies from a map's key or value
type mapItemCopier struct {
dstType reflect.Type
copier copier
}

// Copy implementation of Copy function for map item copier
func (c *mapItemCopier) Copy(src reflect.Value) (reflect.Value, error) {
dst := reflect.New(c.dstType).Elem()
err := c.copier.Copy(dst, src)
Expand Down
7 changes: 7 additions & 0 deletions slice_copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import (
"reflect"
)

// sliceCopier data structure of copier that copies from a `slice`
type sliceCopier struct {
ctx *Context
itemCopier copier
}

// Copy implementation of Copy function for slice copier
func (c *sliceCopier) Copy(dst, src reflect.Value) error {
srcLen := src.Len()
if dst.Kind() == reflect.Slice { // Slice/Array -> Slice
Expand Down Expand Up @@ -76,17 +78,22 @@ func (c *sliceCopier) init(dstType, srcType reflect.Type) (err error) {
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
Expand Down
14 changes: 14 additions & 0 deletions struct_copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ var (
errType = reflect.TypeOf((*error)(nil)).Elem()
)

// structCopier data structure of copier that copies from a `struct`
type structCopier struct {
ctx *Context
fieldCopiers []copier
}

// Copy implementation of Copy function for struct copier
func (c *structCopier) Copy(dst, src reflect.Value) error {
for _, cp := range c.fieldCopiers {
if err := cp.Copy(dst, src); err != nil {
Expand Down Expand Up @@ -201,44 +203,54 @@ func (c *structCopier) createCustomCopier(df, sf *reflect.StructField, cp copier
}
}

// structFieldDirectCopier data structure of copier that copies from
// a src field to a dst field directly
type structFieldDirectCopier struct {
dstField int
srcField int
}

// Copy implementation of Copy function for struct field copier direct
func (c *structFieldDirectCopier) Copy(dst, src reflect.Value) error {
dst.Field(c.dstField).Set(src.Field(c.srcField))
return nil
}

// structFieldConvCopier data structure of copier that copies from
// a src field to a dst field with type conversion
type structFieldConvCopier struct {
dstField int
srcField int
}

// Copy implementation of Copy function for struct field copier with type conversion
func (c *structFieldConvCopier) Copy(dst, src reflect.Value) error {
dstVal := dst.Field(c.dstField)
dstVal.Set(src.Field(c.srcField).Convert(dstVal.Type()))
return nil
}

// structFieldCopier wrapping copier for copying struct field
type structFieldCopier struct {
copier copier
dstField int
srcField int
}

// Copy implementation of Copy function for struct field copier
func (c *structFieldCopier) Copy(dst, src reflect.Value) error {
return c.copier.Copy(dst.Field(c.dstField), src.Field(c.srcField))
}

// structFieldMethodCopier data structure of copier that copies between `fields` and `methods`
type structFieldMethodCopier struct {
dstMethod int
dstMethodUnexported bool
srcField int
srcFieldUnexported bool
}

// Copy implementation of Copy function for struct field copier between `fields` and `methods`
func (c *structFieldMethodCopier) Copy(dst, src reflect.Value) error {
src = src.Field(c.srcField)
if c.srcFieldUnexported {
Expand All @@ -263,6 +275,7 @@ func (c *structFieldMethodCopier) Copy(dst, src reflect.Value) error {
return err
}

// structUnexportedFieldCopier data structure of copier that copies between unexported fields of struct
type structUnexportedFieldCopier struct {
copier copier
dstField int
Expand All @@ -271,6 +284,7 @@ type structUnexportedFieldCopier struct {
srcFieldUnexported bool
}

// Copy implementation of Copy function for struct unexported field copier
func (c *structUnexportedFieldCopier) Copy(dst, src reflect.Value) error {
src = src.Field(c.srcField)
if c.srcFieldUnexported {
Expand Down
2 changes: 2 additions & 0 deletions tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import (
"strings"
)

// fieldDetail stores field copying detail parsed from a struct field
type fieldDetail struct {
field *reflect.StructField
key string
ignored bool
required bool
}

// parseTag parses struct tag for getting copying detail and configuration
func parseTag(detail *fieldDetail) {
tagValue, ok := detail.field.Tag.Lookup(DefaultTagName)
detail.key = detail.field.Name
Expand Down

0 comments on commit fd7c970

Please sign in to comment.