14 // it into the proper DecodeHookFunc type, such as DecodeHookFuncType. |
15 // it into the proper DecodeHookFunc type, such as DecodeHookFuncType. |
15 func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc { |
16 func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc { |
16 // Create variables here so we can reference them with the reflect pkg |
17 // Create variables here so we can reference them with the reflect pkg |
17 var f1 DecodeHookFuncType |
18 var f1 DecodeHookFuncType |
18 var f2 DecodeHookFuncKind |
19 var f2 DecodeHookFuncKind |
|
20 var f3 DecodeHookFuncValue |
19 |
21 |
20 // Fill in the variables into this interface and the rest is done |
22 // Fill in the variables into this interface and the rest is done |
21 // automatically using the reflect package. |
23 // automatically using the reflect package. |
22 potential := []interface{}{f1, f2} |
24 potential := []interface{}{f1, f2, f3} |
23 |
25 |
24 v := reflect.ValueOf(h) |
26 v := reflect.ValueOf(h) |
25 vt := v.Type() |
27 vt := v.Type() |
26 for _, raw := range potential { |
28 for _, raw := range potential { |
27 pt := reflect.ValueOf(raw).Type() |
29 pt := reflect.ValueOf(raw).Type() |
36 // DecodeHookExec executes the given decode hook. This should be used |
38 // DecodeHookExec executes the given decode hook. This should be used |
37 // since it'll naturally degrade to the older backwards compatible DecodeHookFunc |
39 // since it'll naturally degrade to the older backwards compatible DecodeHookFunc |
38 // that took reflect.Kind instead of reflect.Type. |
40 // that took reflect.Kind instead of reflect.Type. |
39 func DecodeHookExec( |
41 func DecodeHookExec( |
40 raw DecodeHookFunc, |
42 raw DecodeHookFunc, |
41 from reflect.Type, to reflect.Type, |
43 from reflect.Value, to reflect.Value) (interface{}, error) { |
42 data interface{}) (interface{}, error) { |
44 |
43 switch f := typedDecodeHook(raw).(type) { |
45 switch f := typedDecodeHook(raw).(type) { |
44 case DecodeHookFuncType: |
46 case DecodeHookFuncType: |
45 return f(from, to, data) |
47 return f(from.Type(), to.Type(), from.Interface()) |
46 case DecodeHookFuncKind: |
48 case DecodeHookFuncKind: |
47 return f(from.Kind(), to.Kind(), data) |
49 return f(from.Kind(), to.Kind(), from.Interface()) |
|
50 case DecodeHookFuncValue: |
|
51 return f(from, to) |
48 default: |
52 default: |
49 return nil, errors.New("invalid decode hook signature") |
53 return nil, errors.New("invalid decode hook signature") |
50 } |
54 } |
51 } |
55 } |
52 |
56 |
54 // automatically composes multiple DecodeHookFuncs. |
58 // automatically composes multiple DecodeHookFuncs. |
55 // |
59 // |
56 // The composed funcs are called in order, with the result of the |
60 // The composed funcs are called in order, with the result of the |
57 // previous transformation. |
61 // previous transformation. |
58 func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { |
62 func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc { |
59 return func( |
63 return func(f reflect.Value, t reflect.Value) (interface{}, error) { |
60 f reflect.Type, |
|
61 t reflect.Type, |
|
62 data interface{}) (interface{}, error) { |
|
63 var err error |
64 var err error |
|
65 var data interface{} |
|
66 newFrom := f |
64 for _, f1 := range fs { |
67 for _, f1 := range fs { |
65 data, err = DecodeHookExec(f1, f, t, data) |
68 data, err = DecodeHookExec(f1, newFrom, t) |
66 if err != nil { |
69 if err != nil { |
67 return nil, err |
70 return nil, err |
68 } |
71 } |
69 |
72 newFrom = reflect.ValueOf(data) |
70 // Modify the from kind to be correct with the new data |
|
71 f = nil |
|
72 if val := reflect.ValueOf(data); val.IsValid() { |
|
73 f = val.Type() |
|
74 } |
|
75 } |
73 } |
76 |
74 |
77 return data, nil |
75 return data, nil |
78 } |
76 } |
79 } |
77 } |
213 } |
211 } |
214 } |
212 } |
215 |
213 |
216 return data, nil |
214 return data, nil |
217 } |
215 } |
|
216 |
|
217 func RecursiveStructToMapHookFunc() DecodeHookFunc { |
|
218 return func(f reflect.Value, t reflect.Value) (interface{}, error) { |
|
219 if f.Kind() != reflect.Struct { |
|
220 return f.Interface(), nil |
|
221 } |
|
222 |
|
223 var i interface{} = struct{}{} |
|
224 if t.Type() != reflect.TypeOf(&i).Elem() { |
|
225 return f.Interface(), nil |
|
226 } |
|
227 |
|
228 m := make(map[string]interface{}) |
|
229 t.Set(reflect.ValueOf(m)) |
|
230 |
|
231 return f.Interface(), nil |
|
232 } |
|
233 } |
|
234 |
|
235 // TextUnmarshallerHookFunc returns a DecodeHookFunc that applies |
|
236 // strings to the UnmarshalText function, when the target type |
|
237 // implements the encoding.TextUnmarshaler interface |
|
238 func TextUnmarshallerHookFunc() DecodeHookFuncType { |
|
239 return func( |
|
240 f reflect.Type, |
|
241 t reflect.Type, |
|
242 data interface{}) (interface{}, error) { |
|
243 if f.Kind() != reflect.String { |
|
244 return data, nil |
|
245 } |
|
246 result := reflect.New(t).Interface() |
|
247 unmarshaller, ok := result.(encoding.TextUnmarshaler) |
|
248 if !ok { |
|
249 return data, nil |
|
250 } |
|
251 if err := unmarshaller.UnmarshalText([]byte(data.(string))); err != nil { |
|
252 return nil, err |
|
253 } |
|
254 return result, nil |
|
255 } |
|
256 } |