Skip to content

Added registration for conversion function to different type#90

Open
tomtwinkle wants to merge 3 commits intojinzhu:masterfrom
tomtwinkle:feature/copy-diffrent-type
Open

Added registration for conversion function to different type#90
tomtwinkle wants to merge 3 commits intojinzhu:masterfrom
tomtwinkle:feature/copy-diffrent-type

Conversation

@tomtwinkle
Copy link
Contributor

@tomtwinkle tomtwinkle commented Mar 5, 2021

Changed so that you can add a function that can be converted to any type.

Can freely customize the type conversion by defining the function for TypeCopier by the user.

type TypePair struct {
	SrcType reflect.Type
	DstType reflect.Type
}

type TypedCopier interface {
	// Define the conversion process
	Copy(dstValue, srcValue reflect.Value) error
	// Defines the type of the source field and the type of the destination field
	Pairs() []TypePair
}

Example

type timeToStringCopier struct{}

func (t timeToStringCopier) Pairs() []copier.TypePair {
	return []copier.TypePair{
		{
			SrcType: reflect.TypeOf(time.Time{}),
			DstType: reflect.TypeOf(""),
		},
		{
			SrcType: reflect.TypeOf(&time.Time{}),
			DstType: reflect.TypeOf(""),
		},
	}
}

func (t timeToStringCopier) Copy(dst, src reflect.Value) error {
	const timeFormat = "2006-01-02T15:04:05.999999999Z07:00"
	if src.Kind() == reflect.Ptr && src.IsNil() {
		if dst.Kind() == reflect.Ptr {
			dst.Set(reflect.Zero(reflect.TypeOf("")))
		}
		return nil
	}

	var val string
	if src.Kind() == reflect.Ptr {
		s, ok := src.Interface().(*time.Time)
		if !ok {
			return errors.New("type not match")
		}
		val = s.Format(timeFormat)
	} else {
		s, ok := src.Interface().(time.Time)
		if !ok {
			return errors.New("type not match")
		}
		val = s.Format(timeFormat)
	}
	dst.Set(reflect.ValueOf(val))
	return nil
}

func main() {
	type SrcStruct1 struct {
		Field1 time.Time
		Field2 *time.Time
	}

	type DestStruct1 struct {
		Field1 string
		Field2 string
	}

	c := copier.NewCopier()
	c.Register(&timeToStringCopier{})

	testTime := time.Date(2021, 3, 5, 1, 30, 0, 123000000, time.UTC)
	src := SrcStruct1{
		Field1: testTime,
		Field2: &testTime,
	}
	var dst DestStruct1

	if err := c.Copy(&dst, src); err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%#v", dst)
	// DestStruct1{Field1:"2021-03-05T01:30:00.123Z", Field2:"2021-03-05T01:30:00.123Z"}
}

@jinzhu
Copy link
Owner

jinzhu commented May 31, 2021

Hello @tomtwinkle

Thank you for your PR, but maybe should pass those registered type in the Option struct? Also might be good to allow to register some default global converters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants