-
Notifications
You must be signed in to change notification settings - Fork 3
/
value_serialization.go
150 lines (139 loc) · 4.45 KB
/
value_serialization.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 ldvalue
import (
"encoding/json"
"errors"
"strconv"
"gopkg.in/launchdarkly/go-sdk-common.v2/jsonstream" //nolint:staticcheck // using a deprecated API
"gopkg.in/launchdarkly/go-jsonstream.v1/jreader"
"gopkg.in/launchdarkly/go-jsonstream.v1/jwriter"
)
// This file contains methods for converting Value to and from JSON.
// Parse returns a Value parsed from a JSON string, or Null if it cannot be parsed.
//
// This is simply a shortcut for calling json.Unmarshal and disregarding errors. It is meant for
// use in test scenarios where malformed data is not a concern.
func Parse(jsonData []byte) Value {
var v Value
if err := v.UnmarshalJSON(jsonData); err != nil {
return Null()
}
return v
}
// JSONString returns the JSON representation of the value.
func (v Value) JSONString() string {
// The following is somewhat redundant with json.Marshal, but it avoids the overhead of
// converting between byte arrays and strings.
switch v.valueType {
case NullType:
return nullAsJSON
case BoolType:
if v.boolValue {
return trueString
}
return falseString
case NumberType:
if v.IsInt() {
return strconv.Itoa(int(v.numberValue))
}
return strconv.FormatFloat(v.numberValue, 'f', -1, 64)
}
// For all other types, we rely on our custom marshaller.
bytes, _ := json.Marshal(v)
// It shouldn't be possible for marshalling to fail, because Value can only contain
// JSON-compatible types. But if it somehow did fail, bytes will be nil and we'll return
// an empty string.
return string(bytes)
}
// MarshalJSON converts the Value to its JSON representation.
//
// Note that the "omitempty" tag for a struct field will not cause an empty Value field to be
// omitted; it will be output as null. If you want to completely omit a JSON property when there
// is no value, it must be a pointer; use AsPointer().
func (v Value) MarshalJSON() ([]byte, error) {
switch v.valueType {
case NullType:
return nullAsJSONBytes, nil
case BoolType:
if v.boolValue {
return trueBytes, nil
}
return falseBytes, nil
case NumberType:
if v.IsInt() {
return []byte(strconv.Itoa(int(v.numberValue))), nil
}
return []byte(strconv.FormatFloat(v.numberValue, 'f', -1, 64)), nil
case StringType:
return json.Marshal(v.stringValue)
case ArrayType:
return v.arrayValue.MarshalJSON()
case ObjectType:
return v.objectValue.MarshalJSON()
case RawType:
return []byte(v.stringValue), nil
}
return nil, errors.New("unknown data type") // should not be possible
}
// UnmarshalJSON parses a Value from JSON.
func (v *Value) UnmarshalJSON(data []byte) error {
return jreader.UnmarshalJSONWithReader(data, v)
}
// ReadFromJSONReader provides JSON deserialization for use with the jsonstream API.
//
// This implementation is used by the SDK in cases where it is more efficient than JSON.Unmarshal.
// See the jsonstream package for more details.
func (v *Value) ReadFromJSONReader(r *jreader.Reader) {
a := r.Any()
if r.Error() != nil {
return
}
switch a.Kind {
case jreader.BoolValue:
*v = Bool(a.Bool)
case jreader.NumberValue:
*v = Float64(a.Number)
case jreader.StringValue:
*v = String(a.String)
case jreader.ArrayValue:
var va ValueArray
if va.readFromJSONArray(r, &a.Array); r.Error() == nil {
*v = Value{valueType: ArrayType, arrayValue: va}
}
case jreader.ObjectValue:
var vm ValueMap
if vm.readFromJSONObject(r, &a.Object); r.Error() == nil {
*v = Value{valueType: ObjectType, objectValue: vm}
}
default:
*v = Null()
}
}
// WriteToJSONWriter provides JSON serialization for use with the jsonstream API.
//
// This implementation is used by the SDK in cases where it is more efficient than JSON.Marshal.
// See https://github.com/launchdarkly/go-jsonstream for more details.
func (v Value) WriteToJSONWriter(w *jwriter.Writer) {
switch v.valueType {
case NullType:
w.Null()
case BoolType:
w.Bool(v.boolValue)
case NumberType:
w.Float64(v.numberValue)
case StringType:
w.String(v.stringValue)
case ArrayType:
v.arrayValue.WriteToJSONWriter(w)
case ObjectType:
v.objectValue.WriteToJSONWriter(w)
case RawType:
w.Raw([]byte(v.stringValue))
}
}
// WriteToJSONBuffer provides JSON serialization for use with the deprecated jsonstream API.
//
// Deprecated: this method is provided for backward compatibility. The LaunchDarkly SDK no longer
// uses this API; instead it uses the newer https://github.com/launchdarkly/go-jsonstream.
func (v Value) WriteToJSONBuffer(j *jsonstream.JSONBuffer) {
jsonstream.WriteToJSONBufferThroughWriter(v, j)
}