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
|
package json
import (
"bytes"
"encoding/base64"
"math/big"
"strconv"
"github.com/aws/smithy-go/encoding"
)
// Value represents a JSON Value type
// JSON Value types: Object, Array, String, Number, Boolean, and Null
type Value struct {
w *bytes.Buffer
scratch *[]byte
}
// newValue returns a new Value encoder
func newValue(w *bytes.Buffer, scratch *[]byte) Value {
return Value{w: w, scratch: scratch}
}
// String encodes v as a JSON string
func (jv Value) String(v string) {
escapeStringBytes(jv.w, []byte(v))
}
// Byte encodes v as a JSON number
func (jv Value) Byte(v int8) {
jv.Long(int64(v))
}
// Short encodes v as a JSON number
func (jv Value) Short(v int16) {
jv.Long(int64(v))
}
// Integer encodes v as a JSON number
func (jv Value) Integer(v int32) {
jv.Long(int64(v))
}
// Long encodes v as a JSON number
func (jv Value) Long(v int64) {
*jv.scratch = strconv.AppendInt((*jv.scratch)[:0], v, 10)
jv.w.Write(*jv.scratch)
}
// ULong encodes v as a JSON number
func (jv Value) ULong(v uint64) {
*jv.scratch = strconv.AppendUint((*jv.scratch)[:0], v, 10)
jv.w.Write(*jv.scratch)
}
// Float encodes v as a JSON number
func (jv Value) Float(v float32) {
jv.float(float64(v), 32)
}
// Double encodes v as a JSON number
func (jv Value) Double(v float64) {
jv.float(v, 64)
}
func (jv Value) float(v float64, bits int) {
*jv.scratch = encoding.EncodeFloat((*jv.scratch)[:0], v, bits)
jv.w.Write(*jv.scratch)
}
// Boolean encodes v as a JSON boolean
func (jv Value) Boolean(v bool) {
*jv.scratch = strconv.AppendBool((*jv.scratch)[:0], v)
jv.w.Write(*jv.scratch)
}
// Base64EncodeBytes writes v as a base64 value in JSON string
func (jv Value) Base64EncodeBytes(v []byte) {
encodeByteSlice(jv.w, (*jv.scratch)[:0], v)
}
// Write writes v directly to the JSON document
func (jv Value) Write(v []byte) {
jv.w.Write(v)
}
// Array returns a new Array encoder
func (jv Value) Array() *Array {
return newArray(jv.w, jv.scratch)
}
// Object returns a new Object encoder
func (jv Value) Object() *Object {
return newObject(jv.w, jv.scratch)
}
// Null encodes a null JSON value
func (jv Value) Null() {
jv.w.WriteString(null)
}
// BigInteger encodes v as JSON value
func (jv Value) BigInteger(v *big.Int) {
jv.w.Write([]byte(v.Text(10)))
}
// BigDecimal encodes v as JSON value
func (jv Value) BigDecimal(v *big.Float) {
if i, accuracy := v.Int64(); accuracy == big.Exact {
jv.Long(i)
return
}
// TODO: Should this try to match ES6 ToString similar to stdlib JSON?
jv.w.Write([]byte(v.Text('e', -1)))
}
// Based on encoding/json encodeByteSlice from the Go Standard Library
// https://golang.org/src/encoding/json/encode.go
func encodeByteSlice(w *bytes.Buffer, scratch []byte, v []byte) {
if v == nil {
w.WriteString(null)
return
}
w.WriteRune(quote)
encodedLen := base64.StdEncoding.EncodedLen(len(v))
if encodedLen <= len(scratch) {
// If the encoded bytes fit in e.scratch, avoid an extra
// allocation and use the cheaper Encoding.Encode.
dst := scratch[:encodedLen]
base64.StdEncoding.Encode(dst, v)
w.Write(dst)
} else if encodedLen <= 1024 {
// The encoded bytes are short enough to allocate for, and
// Encoding.Encode is still cheaper.
dst := make([]byte, encodedLen)
base64.StdEncoding.Encode(dst, v)
w.Write(dst)
} else {
// The encoded bytes are too long to cheaply allocate, and
// Encoding.Encode is no longer noticeably cheaper.
enc := base64.NewEncoder(base64.StdEncoding, w)
enc.Write(v)
enc.Close()
}
w.WriteRune(quote)
}
|