OSDN Git Service

Wallet store test (#312)
[bytom/vapor.git] / vendor / github.com / tendermint / go-wire / data / json.go
1 package data
2
3 import (
4         "bytes"
5         "encoding/json"
6         "reflect"
7
8         "github.com/pkg/errors"
9 )
10
11 type jsonMapper struct {
12         kindToType map[string]reflect.Type
13         typeToKind map[reflect.Type]string
14 }
15
16 func newJsonMapper(base interface{}) *jsonMapper {
17         return &jsonMapper{
18                 kindToType: map[string]reflect.Type{},
19                 typeToKind: map[reflect.Type]string{},
20         }
21 }
22
23 // ToJSON is a convenience method to serialize with encoding/json
24 func ToJSON(o interface{}) ([]byte, error) {
25         d, err := json.MarshalIndent(o, "", "  ")
26         return d, errors.WithStack(err)
27 }
28
29 // FromJSON is a convenience method to deserialize with encoding/json
30 func FromJSON(d []byte, o interface{}) error {
31         return errors.WithStack(
32                 json.Unmarshal(d, o))
33 }
34
35 // registerImplementation allows you to register multiple concrete types.
36 //
37 // Returns itself to allow calls to be chained
38 func (m *jsonMapper) registerImplementation(data interface{}, kind string, b byte) {
39         typ := reflect.TypeOf(data)
40         m.kindToType[kind] = typ
41         m.typeToKind[typ] = kind
42 }
43
44 // getTarget returns a pointer to an allocated object of the proper kind
45 func (m *jsonMapper) getTarget(kind string) (interface{}, error) {
46         typ, ok := m.kindToType[kind]
47         if !ok {
48                 return nil, errors.Errorf("Unmarshaling into unknown type: %s", kind)
49         }
50         target := reflect.New(typ).Interface()
51         return target, nil
52 }
53
54 func (m *jsonMapper) getKind(obj interface{}) (string, error) {
55         typ := reflect.TypeOf(obj)
56         kind, ok := m.typeToKind[typ]
57         if !ok {
58                 return "", errors.Errorf("Marshalling from unknown type: %#v", obj)
59         }
60         return kind, nil
61 }
62
63 // FromJSON will deserialize the output of ToJSON for every registered
64 // implementation of the interface
65 func (m *jsonMapper) FromJSON(data []byte) (interface{}, error) {
66         // handle null specially
67         if bytes.Equal(data, []byte("null")) {
68                 return nil, nil
69         }
70         e := envelope{
71                 Data: &json.RawMessage{},
72         }
73         err := json.Unmarshal(data, &e)
74         if err != nil {
75                 return nil, err
76         }
77         // switch on the type, then unmarshal into that
78         bytes := *e.Data.(*json.RawMessage)
79         res, err := m.getTarget(e.Kind)
80         if err != nil {
81                 return nil, err
82         }
83         err = json.Unmarshal(bytes, &res)
84         // getTarget returned a pointer for Unmarshall, now dereference it
85         res = reflect.ValueOf(res).Elem().Interface()
86         return res, err
87 }
88
89 // ToJson will serialize a registered implementation into a format like:
90 //   {
91 //     "type": "foo",
92 //     "data": {
93 //       "name": "dings"
94 //     }
95 //   }
96 // this allows us to properly deserialize with FromJSON
97 func (m *jsonMapper) ToJSON(data interface{}) ([]byte, error) {
98         // handle null specially
99         if data == nil {
100                 return []byte("null"), nil
101         }
102         raw, err := json.Marshal(data)
103         if err != nil {
104                 return nil, errors.WithStack(err)
105         }
106         kind, err := m.getKind(data)
107         if err != nil {
108                 return nil, err
109         }
110         msg := json.RawMessage(raw)
111         e := envelope{
112                 Kind: kind,
113                 Data: &msg,
114         }
115         return json.Marshal(e)
116 }
117
118 // envelope lets us switch on type
119 type envelope struct {
120         Kind string      `json:"type"`
121         Data interface{} `json:"data"`
122 }