forked from s7techlab/cckit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
convert.go
150 lines (125 loc) · 4 KB
/
convert.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
144
145
146
147
148
149
150
// Package convert for transforming between json serialized []byte and go structs
package convert
import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer"
"github.com/pkg/errors"
)
var (
// ErrUnableToConvertNilToStruct - nil cannot be converted to struct
ErrUnableToConvertNilToStruct = errors.New(`unable to convert nil to [struct,array,slice,ptr]`)
// ErrUnableToConvertValueToStruct - value cannot be converted to struct
ErrUnableToConvertValueToStruct = errors.New(`unable to convert value to [struct,array,slice,ptr]`)
)
// FromByter interface supports FromBytes func for converting to structure
type FromByter interface {
FromBytes([]byte) (interface{}, error)
}
// ToByter interface supports ToBytes func, marshalling to []byte (json.Marshall)
type ToByter interface {
ToBytes() ([]byte, error)
}
// FromBytes converts []byte to target interface
func FromBytes(bb []byte, target interface{}) (result interface{}, err error) {
switch target.(type) {
case string:
return string(bb), nil
case []byte:
return bb, nil
case int:
return strconv.Atoi(string(bb))
case FromByter:
return target.(FromByter).FromBytes(bb)
default:
return FromBytesToStruct(bb, target)
}
}
// FromResponse converts response.Payload to target
func FromResponse(response peer.Response, target interface{}) (result interface{}, err error) {
if response.Status == shim.ERROR {
return nil, errors.New(response.Message)
}
return FromBytes(response.Payload, target)
}
// FromBytesToStruct converts []byte to struct,array,slice depending on target type
func FromBytesToStruct(bb []byte, target interface{}) (result interface{}, err error) {
if bb == nil {
return nil, ErrUnableToConvertNilToStruct
}
targetType := reflect.TypeOf(target).Kind()
switch targetType {
case reflect.Struct:
fallthrough
case reflect.Array:
fallthrough
case reflect.Slice:
// will be map[string]interface{}
return UnmarshallPtr(bb, &target)
case reflect.Ptr:
return UnmarshallPtr(bb, target)
default:
return nil, fmt.Errorf(
`toBytes converting supports ToByter interface,struct,array,slice and string, current type is %s`,
targetType)
}
}
// UnmarshallPtr unmarshalls [] byte to pointer, and returns value pointed to
func UnmarshallPtr(bb []byte, targetPtr interface{}) (result interface{}, err error) {
err = json.Unmarshal(bb, targetPtr)
if err != nil {
return nil, errors.Wrap(err, ErrUnableToConvertValueToStruct.Error())
}
return reflect.Indirect(reflect.ValueOf(targetPtr)).Interface(), nil
}
// ToBytes converts inteface{} (string, []byte , struct to ToByter interface to []byte for storing in state
func ToBytes(value interface{}) ([]byte, error) {
switch value.(type) {
// first priority if value implements ToByter interface
case ToByter:
return value.(ToByter).ToBytes()
case string:
return []byte(value.(string)), nil
case uint:
return []byte(fmt.Sprint(value.(uint))), nil
case int:
return []byte(fmt.Sprint(value.(int))), nil
case []byte:
return value.([]byte), nil
default:
valueType := reflect.TypeOf(value).Kind()
switch valueType {
case reflect.Ptr:
fallthrough
case reflect.Struct:
fallthrough
case reflect.Array:
fallthrough
case reflect.Slice:
//TODO: problems when struct includes anonymous struct - anonymous struct is in separate field
return json.Marshal(value)
// used when type based on string
case reflect.String:
return []byte(reflect.ValueOf(value).String()), nil
default:
return nil, fmt.Errorf(
`toBytes converting supports ToByter interface,struct,array,slice and string, current type is %s`,
valueType)
}
}
}
// ArgsToBytes converts func arguments to bytes
func ArgsToBytes(iargs ...interface{}) (aa [][]byte, err error) {
args := make([][]byte, len(iargs))
for i, arg := range iargs {
val, err := ToBytes(arg)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf(`unable to convert invoke arg[%d]`, i))
}
args[i] = val
}
return args, nil
}