...
1 package blackmagic
2
3 import (
4 "fmt"
5 "reflect"
6 )
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 func AssignOptionalField(dst, src interface{}) error {
26 dstRV := reflect.ValueOf(dst)
27 srcRV := reflect.ValueOf(src)
28 if dstRV.Kind() != reflect.Pointer || dstRV.Elem().Kind() != reflect.Pointer {
29 return fmt.Errorf(`dst must be a pointer to a field that is turn a pointer of src (%T)`, src)
30 }
31
32 if !dstRV.Elem().CanSet() {
33 return fmt.Errorf(`dst (%T) is not assignable`, dstRV.Elem().Interface())
34 }
35 if !reflect.PtrTo(srcRV.Type()).AssignableTo(dstRV.Elem().Type()) {
36 return fmt.Errorf(`cannot assign src (%T) to dst (%T)`, src, dst)
37 }
38
39 ptr := reflect.New(srcRV.Type())
40 ptr.Elem().Set(srcRV)
41 dstRV.Elem().Set(ptr)
42 return nil
43 }
44
45
46
47
48
49 func AssignIfCompatible(dst, src interface{}) error {
50 orv := reflect.ValueOf(src)
51 result := orv
52
53
54
55 var isPtr bool
56 var isSlice bool
57 switch result.Kind() {
58 case reflect.Ptr:
59 isPtr = true
60 case reflect.Slice:
61 isSlice = true
62 }
63
64 rv := reflect.ValueOf(dst)
65 if rv.Kind() != reflect.Ptr {
66 return fmt.Errorf(`destination argument to AssignIfCompatible() must be a pointer: %T`, dst)
67 }
68
69 actualDst := rv.Elem()
70 switch actualDst.Kind() {
71 case reflect.Interface:
72
73 default:
74
75
76 if !isSlice && isPtr {
77 result = result.Elem()
78 }
79 }
80 if !result.Type().AssignableTo(actualDst.Type()) {
81 return fmt.Errorf(`argument to AssignIfCompatible() must be compatible with %T (was %T)`, orv.Interface(), dst)
82 }
83
84 if !actualDst.CanSet() {
85 return fmt.Errorf(`argument to AssignIfCompatible() must be settable`)
86 }
87 actualDst.Set(result)
88
89 return nil
90 }
91
View as plain text