1
16
17 package conversion
18
19 import (
20 "fmt"
21 "reflect"
22 )
23
24 type typePair struct {
25 source reflect.Type
26 dest reflect.Type
27 }
28
29 type NameFunc func(t reflect.Type) string
30
31 var DefaultNameFunc = func(t reflect.Type) string { return t.Name() }
32
33
34
35
36
37 type ConversionFunc func(a, b interface{}, scope Scope) error
38
39
40 type Converter struct {
41
42
43 conversionFuncs ConversionFuncs
44 generatedConversionFuncs ConversionFuncs
45
46
47 ignoredUntypedConversions map[typePair]struct{}
48 }
49
50
51
52 func NewConverter(NameFunc) *Converter {
53 c := &Converter{
54 conversionFuncs: NewConversionFuncs(),
55 generatedConversionFuncs: NewConversionFuncs(),
56 ignoredUntypedConversions: make(map[typePair]struct{}),
57 }
58 c.RegisterUntypedConversionFunc(
59 (*[]byte)(nil), (*[]byte)(nil),
60 func(a, b interface{}, s Scope) error {
61 return Convert_Slice_byte_To_Slice_byte(a.(*[]byte), b.(*[]byte), s)
62 },
63 )
64 return c
65 }
66
67
68
69 func (c *Converter) WithConversions(fns ConversionFuncs) *Converter {
70 copied := *c
71 copied.conversionFuncs = c.conversionFuncs.Merge(fns)
72 return &copied
73 }
74
75
76 func (c *Converter) DefaultMeta(t reflect.Type) *Meta {
77 return &Meta{}
78 }
79
80
81 func Convert_Slice_byte_To_Slice_byte(in *[]byte, out *[]byte, s Scope) error {
82 if *in == nil {
83 *out = nil
84 return nil
85 }
86 *out = make([]byte, len(*in))
87 copy(*out, *in)
88 return nil
89 }
90
91
92
93
94 type Scope interface {
95
96
97 Convert(src, dest interface{}) error
98
99
100 Meta() *Meta
101 }
102
103 func NewConversionFuncs() ConversionFuncs {
104 return ConversionFuncs{
105 untyped: make(map[typePair]ConversionFunc),
106 }
107 }
108
109 type ConversionFuncs struct {
110 untyped map[typePair]ConversionFunc
111 }
112
113
114
115
116 func (c ConversionFuncs) AddUntyped(a, b interface{}, fn ConversionFunc) error {
117 tA, tB := reflect.TypeOf(a), reflect.TypeOf(b)
118 if tA.Kind() != reflect.Pointer {
119 return fmt.Errorf("the type %T must be a pointer to register as an untyped conversion", a)
120 }
121 if tB.Kind() != reflect.Pointer {
122 return fmt.Errorf("the type %T must be a pointer to register as an untyped conversion", b)
123 }
124 c.untyped[typePair{tA, tB}] = fn
125 return nil
126 }
127
128
129
130 func (c ConversionFuncs) Merge(other ConversionFuncs) ConversionFuncs {
131 merged := NewConversionFuncs()
132 for k, v := range c.untyped {
133 merged.untyped[k] = v
134 }
135 for k, v := range other.untyped {
136 merged.untyped[k] = v
137 }
138 return merged
139 }
140
141
142 type Meta struct {
143
144 Context interface{}
145 }
146
147
148 type scope struct {
149 converter *Converter
150 meta *Meta
151 }
152
153
154 func (s *scope) Convert(src, dest interface{}) error {
155 return s.converter.Convert(src, dest, s.meta)
156 }
157
158
159 func (s *scope) Meta() *Meta {
160 return s.meta
161 }
162
163
164
165
166 func (c *Converter) RegisterUntypedConversionFunc(a, b interface{}, fn ConversionFunc) error {
167 return c.conversionFuncs.AddUntyped(a, b, fn)
168 }
169
170
171
172
173 func (c *Converter) RegisterGeneratedUntypedConversionFunc(a, b interface{}, fn ConversionFunc) error {
174 return c.generatedConversionFuncs.AddUntyped(a, b, fn)
175 }
176
177
178
179 func (c *Converter) RegisterIgnoredConversion(from, to interface{}) error {
180 typeFrom := reflect.TypeOf(from)
181 typeTo := reflect.TypeOf(to)
182 if typeFrom.Kind() != reflect.Pointer {
183 return fmt.Errorf("expected pointer arg for 'from' param 0, got: %v", typeFrom)
184 }
185 if typeTo.Kind() != reflect.Pointer {
186 return fmt.Errorf("expected pointer arg for 'to' param 1, got: %v", typeTo)
187 }
188 c.ignoredUntypedConversions[typePair{typeFrom, typeTo}] = struct{}{}
189 return nil
190 }
191
192
193
194
195
196
197
198 func (c *Converter) Convert(src, dest interface{}, meta *Meta) error {
199 pair := typePair{reflect.TypeOf(src), reflect.TypeOf(dest)}
200 scope := &scope{
201 converter: c,
202 meta: meta,
203 }
204
205
206 if _, ok := c.ignoredUntypedConversions[pair]; ok {
207 return nil
208 }
209 if fn, ok := c.conversionFuncs.untyped[pair]; ok {
210 return fn(src, dest, scope)
211 }
212 if fn, ok := c.generatedConversionFuncs.untyped[pair]; ok {
213 return fn(src, dest, scope)
214 }
215
216 dv, err := EnforcePtr(dest)
217 if err != nil {
218 return err
219 }
220 sv, err := EnforcePtr(src)
221 if err != nil {
222 return err
223 }
224 return fmt.Errorf("converting (%s) to (%s): unknown conversion", sv.Type(), dv.Type())
225 }
226
View as plain text