-
Notifications
You must be signed in to change notification settings - Fork 113
/
serializer.go
143 lines (127 loc) · 3.12 KB
/
serializer.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package database
import (
"encoding/binary"
"errors"
"strings"
"github.com/iost-official/go-iost/common"
)
// const prefixs
const (
IntPrefix = "i"
StringPrefix = "s"
NilPrefix = "n"
BoolPrefix = "b"
JSONPrefix = "j"
MapHolderPrefix = "@"
FixPointPrefix = "f"
)
var (
errTypeNotSupport = errors.New("type not support")
errInvalidData = errors.New("invalid data")
)
// SerializedJSON type of Serialized json
type SerializedJSON []byte
// Marshal marshal go types to value string
func Marshal(in interface{}, extras ...string) (string, error) {
extra := ""
if len(extras) > 0 {
extra = extras[0]
}
switch in := in.(type) {
case int64:
return IntPrefix + int64ToRaw(in) + ApplicationSeparator + extra, nil
case string:
return StringPrefix + in + ApplicationSeparator + extra, nil
case nil:
return NilPrefix, nil
case bool:
return BoolPrefix + boolToString(in) + ApplicationSeparator + extra, nil
case SerializedJSON:
return JSONPrefix + string(in) + ApplicationSeparator + extra, nil
case *common.Fixed:
return FixPointPrefix + in.Marshal() + ApplicationSeparator + extra, nil
}
return "", errTypeNotSupport
}
// MustMarshal marshal go types to value string, panic on error
func MustMarshal(in interface{}, extra ...string) string {
s, err := Marshal(in, extra...)
if err != nil {
panic(err)
}
return s
}
// unmarshalInner unmarshal value string to go types
func unmarshalInner(o string) interface{} {
if len(o) < 1 {
return errInvalidData
}
switch o[0:1] {
case IntPrefix:
return rawToInt64(o[1:])
case StringPrefix:
return o[1:]
case NilPrefix:
return nil
case BoolPrefix:
return o[1] == 't'
case JSONPrefix:
return SerializedJSON(o[1:])
case MapHolderPrefix:
return strings.Split(o, "@")[1:]
case FixPointPrefix:
ret, err := common.UnmarshalFixed(o[1:])
if err != nil {
return err
}
return ret
}
return errInvalidData
}
// Unmarshal unmarshal value string to go types
func Unmarshal(o string) interface{} {
idx := strings.LastIndex(o, ApplicationSeparator)
if idx == -1 {
return unmarshalInner(o)
}
return unmarshalInner(o[0:idx])
}
// UnmarshalWithExtra unmarshal value string to go types
func UnmarshalWithExtra(o string) (interface{}, string) {
idx := strings.LastIndex(o, ApplicationSeparator)
if idx == -1 {
return unmarshalInner(o), ""
}
return unmarshalInner(o[0:idx]), o[idx+1:]
}
// MustUnmarshal unmarshal value string to go types, panic on error
func MustUnmarshal(o string) interface{} {
rtn := Unmarshal(o)
if err, ok := rtn.(error); ok {
panic(err.Error() + ":" + o)
}
return rtn
}
// MustUnmarshalWithExtra unmarshal value string to go types, panic on error
func MustUnmarshalWithExtra(o string) (interface{}, string) {
rtn, extra := UnmarshalWithExtra(o)
if err, ok := rtn.(error); ok {
panic(err.Error() + ":" + o)
}
return rtn, extra
}
func int64ToRaw(i int64) string {
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(i))
return string(b)
}
func rawToInt64(s string) int64 {
b := []byte(s)
return int64(binary.LittleEndian.Uint64(b))
}
func boolToString(i bool) string {
if i {
return "t"
}
return "f"
}