-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
marshalers.go
110 lines (97 loc) · 2.56 KB
/
marshalers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package tagflag
import (
"fmt"
"reflect"
"strconv"
"github.com/pkg/errors"
)
// TODO: Perhaps this should embed encoding.TextUnmarshaler instead.
type Marshaler interface {
Marshal(in string) error
// Must have and ignore a pointer receiver.
RequiresExplicitValue() bool
}
type marshaler interface {
Marshal(reflect.Value, string) error
RequiresExplicitValue() bool
}
type dynamicMarshaler struct {
explicitValueRequired bool
marshal func(reflect.Value, string) error
}
func (me dynamicMarshaler) Marshal(v reflect.Value, s string) error {
return me.marshal(v, s)
}
func (me dynamicMarshaler) RequiresExplicitValue() bool {
return me.explicitValueRequired
}
// The fallback marshaler, that attempts to use fmt.Sscan, and recursion to
// sort marshal types.
type defaultMarshaler struct{}
func (defaultMarshaler) Marshal(v reflect.Value, s string) error {
switch v.Kind() {
case reflect.Slice:
n := reflect.New(v.Type().Elem())
m := valueMarshaler(n.Elem().Type())
if m == nil {
return fmt.Errorf("can't marshal type %s", n.Elem().Type())
}
err := m.Marshal(n.Elem(), s)
if err != nil {
return err
}
v.Set(reflect.Append(v, n.Elem()))
return nil
case reflect.Int:
x, err := strconv.ParseInt(s, 0, 0)
v.SetInt(x)
return err
case reflect.Uint:
x, err := strconv.ParseUint(s, 0, 0)
v.SetUint(x)
return err
case reflect.Int64:
x, err := strconv.ParseInt(s, 0, 64)
v.SetInt(x)
return err
case reflect.String:
v.SetString(s)
return nil
case reflect.Array:
if v.Type().Elem().Kind() == reflect.Uint8 {
if len(s) == 2*v.Len() {
var sl []byte = v.Slice(0, v.Len()).Interface().([]byte)
// log.Println(cap(sl), len(sl))
// hex.DecodeString(s)
_, err := fmt.Sscanf(s, "%x", &sl)
// log.Println(cap(sl), sl, err)
if err != nil {
return errors.Wrapf(err, "scanning hex")
}
// Seems the slice moves as part of the decoding :|
reflect.Copy(v, reflect.ValueOf(sl))
} else {
return errors.Errorf("argument has unhandled length %d", len(s))
}
return nil
} else {
return errors.Errorf("unhandled array elem type: %s", v.Type().String())
}
default:
return fmt.Errorf("unhandled builtin type: %s", v.Type().String())
}
}
func (defaultMarshaler) RequiresExplicitValue() bool {
return true
}
type ptrMarshaler struct {
inner marshaler
}
func (me ptrMarshaler) Marshal(v reflect.Value, s string) error {
elemValue := reflect.New(v.Type().Elem())
v.Set(elemValue)
return me.inner.Marshal(elemValue.Elem(), s)
}
func (me ptrMarshaler) RequiresExplicitValue() bool {
return false
}