1 // Package jwriter contains a JSON writer.
9 "github.com/mailru/easyjson/buffer"
12 // Flags describe various encoding options. The behavior may be actually implemented in the encoder, but
13 // Flags field in Writer is used to set and pass them around.
17 NilMapAsEmpty Flags = 1 << iota // Encode nil map as '{}' rather than 'null'.
18 NilSliceAsEmpty // Encode nil slice as '[]' rather than 'null'.
21 // Writer is a JSON writer.
30 // Size returns the size of the data that was written out.
31 func (w *Writer) Size() int {
32 return w.Buffer.Size()
35 // DumpTo outputs the data to given io.Writer, resetting the buffer.
36 func (w *Writer) DumpTo(out io.Writer) (written int, err error) {
37 return w.Buffer.DumpTo(out)
40 // BuildBytes returns writer data as a single byte slice. You can optionally provide one byte slice
41 // as argument that it will try to reuse.
42 func (w *Writer) BuildBytes(reuse ...[]byte) ([]byte, error) {
47 return w.Buffer.BuildBytes(reuse...), nil
50 // ReadCloser returns an io.ReadCloser that can be used to read the data.
51 // ReadCloser also resets the buffer.
52 func (w *Writer) ReadCloser() (io.ReadCloser, error) {
57 return w.Buffer.ReadCloser(), nil
60 // RawByte appends raw binary data to the buffer.
61 func (w *Writer) RawByte(c byte) {
62 w.Buffer.AppendByte(c)
65 // RawByte appends raw binary data to the buffer.
66 func (w *Writer) RawString(s string) {
67 w.Buffer.AppendString(s)
70 // Raw appends raw binary data to the buffer or sets the error if it is given. Useful for
71 // calling with results of MarshalJSON-like functions.
72 func (w *Writer) Raw(data []byte, err error) {
79 w.Buffer.AppendBytes(data)
85 // RawText encloses raw binary data in quotes and appends in to the buffer.
86 // Useful for calling with results of MarshalText-like functions.
87 func (w *Writer) RawText(data []byte, err error) {
94 w.String(string(data))
100 // Base64Bytes appends data to the buffer after base64 encoding it
101 func (w *Writer) Base64Bytes(data []byte) {
103 w.Buffer.AppendString("null")
106 w.Buffer.AppendByte('"')
108 w.Buffer.AppendByte('"')
111 func (w *Writer) Uint8(n uint8) {
112 w.Buffer.EnsureSpace(3)
113 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
116 func (w *Writer) Uint16(n uint16) {
117 w.Buffer.EnsureSpace(5)
118 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
121 func (w *Writer) Uint32(n uint32) {
122 w.Buffer.EnsureSpace(10)
123 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
126 func (w *Writer) Uint(n uint) {
127 w.Buffer.EnsureSpace(20)
128 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
131 func (w *Writer) Uint64(n uint64) {
132 w.Buffer.EnsureSpace(20)
133 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, n, 10)
136 func (w *Writer) Int8(n int8) {
137 w.Buffer.EnsureSpace(4)
138 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
141 func (w *Writer) Int16(n int16) {
142 w.Buffer.EnsureSpace(6)
143 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
146 func (w *Writer) Int32(n int32) {
147 w.Buffer.EnsureSpace(11)
148 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
151 func (w *Writer) Int(n int) {
152 w.Buffer.EnsureSpace(21)
153 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
156 func (w *Writer) Int64(n int64) {
157 w.Buffer.EnsureSpace(21)
158 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, n, 10)
161 func (w *Writer) Uint8Str(n uint8) {
162 w.Buffer.EnsureSpace(3)
163 w.Buffer.Buf = append(w.Buffer.Buf, '"')
164 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
165 w.Buffer.Buf = append(w.Buffer.Buf, '"')
168 func (w *Writer) Uint16Str(n uint16) {
169 w.Buffer.EnsureSpace(5)
170 w.Buffer.Buf = append(w.Buffer.Buf, '"')
171 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
172 w.Buffer.Buf = append(w.Buffer.Buf, '"')
175 func (w *Writer) Uint32Str(n uint32) {
176 w.Buffer.EnsureSpace(10)
177 w.Buffer.Buf = append(w.Buffer.Buf, '"')
178 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
179 w.Buffer.Buf = append(w.Buffer.Buf, '"')
182 func (w *Writer) UintStr(n uint) {
183 w.Buffer.EnsureSpace(20)
184 w.Buffer.Buf = append(w.Buffer.Buf, '"')
185 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
186 w.Buffer.Buf = append(w.Buffer.Buf, '"')
189 func (w *Writer) Uint64Str(n uint64) {
190 w.Buffer.EnsureSpace(20)
191 w.Buffer.Buf = append(w.Buffer.Buf, '"')
192 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, n, 10)
193 w.Buffer.Buf = append(w.Buffer.Buf, '"')
196 func (w *Writer) UintptrStr(n uintptr) {
197 w.Buffer.EnsureSpace(20)
198 w.Buffer.Buf = append(w.Buffer.Buf, '"')
199 w.Buffer.Buf = strconv.AppendUint(w.Buffer.Buf, uint64(n), 10)
200 w.Buffer.Buf = append(w.Buffer.Buf, '"')
203 func (w *Writer) Int8Str(n int8) {
204 w.Buffer.EnsureSpace(4)
205 w.Buffer.Buf = append(w.Buffer.Buf, '"')
206 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
207 w.Buffer.Buf = append(w.Buffer.Buf, '"')
210 func (w *Writer) Int16Str(n int16) {
211 w.Buffer.EnsureSpace(6)
212 w.Buffer.Buf = append(w.Buffer.Buf, '"')
213 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
214 w.Buffer.Buf = append(w.Buffer.Buf, '"')
217 func (w *Writer) Int32Str(n int32) {
218 w.Buffer.EnsureSpace(11)
219 w.Buffer.Buf = append(w.Buffer.Buf, '"')
220 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
221 w.Buffer.Buf = append(w.Buffer.Buf, '"')
224 func (w *Writer) IntStr(n int) {
225 w.Buffer.EnsureSpace(21)
226 w.Buffer.Buf = append(w.Buffer.Buf, '"')
227 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, int64(n), 10)
228 w.Buffer.Buf = append(w.Buffer.Buf, '"')
231 func (w *Writer) Int64Str(n int64) {
232 w.Buffer.EnsureSpace(21)
233 w.Buffer.Buf = append(w.Buffer.Buf, '"')
234 w.Buffer.Buf = strconv.AppendInt(w.Buffer.Buf, n, 10)
235 w.Buffer.Buf = append(w.Buffer.Buf, '"')
238 func (w *Writer) Float32(n float32) {
239 w.Buffer.EnsureSpace(20)
240 w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32)
243 func (w *Writer) Float32Str(n float32) {
244 w.Buffer.EnsureSpace(20)
245 w.Buffer.Buf = append(w.Buffer.Buf, '"')
246 w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 32)
247 w.Buffer.Buf = append(w.Buffer.Buf, '"')
250 func (w *Writer) Float64(n float64) {
251 w.Buffer.EnsureSpace(20)
252 w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, n, 'g', -1, 64)
255 func (w *Writer) Float64Str(n float64) {
256 w.Buffer.EnsureSpace(20)
257 w.Buffer.Buf = append(w.Buffer.Buf, '"')
258 w.Buffer.Buf = strconv.AppendFloat(w.Buffer.Buf, float64(n), 'g', -1, 64)
259 w.Buffer.Buf = append(w.Buffer.Buf, '"')
262 func (w *Writer) Bool(v bool) {
263 w.Buffer.EnsureSpace(5)
265 w.Buffer.Buf = append(w.Buffer.Buf, "true"...)
267 w.Buffer.Buf = append(w.Buffer.Buf, "false"...)
271 const chars = "0123456789abcdef"
273 func isNotEscapedSingleChar(c byte, escapeHTML bool) bool {
274 // Note: might make sense to use a table if there are more chars to escape. With 4 chars
275 // it benchmarks the same.
277 return c != '<' && c != '>' && c != '&' && c != '\\' && c != '"' && c >= 0x20 && c < utf8.RuneSelf
279 return c != '\\' && c != '"' && c >= 0x20 && c < utf8.RuneSelf
283 func (w *Writer) String(s string) {
284 w.Buffer.AppendByte('"')
286 // Portions of the string that contain no escapes are appended as
289 p := 0 // last non-escape symbol
291 for i := 0; i < len(s); {
294 if isNotEscapedSingleChar(c, !w.NoEscapeHTML) {
295 // single-width character, no escaping is required
298 } else if c < utf8.RuneSelf {
299 // single-with character, need to escape
300 w.Buffer.AppendString(s[p:i])
303 w.Buffer.AppendString(`\t`)
305 w.Buffer.AppendString(`\r`)
307 w.Buffer.AppendString(`\n`)
309 w.Buffer.AppendString(`\\`)
311 w.Buffer.AppendString(`\"`)
313 w.Buffer.AppendString(`\u00`)
314 w.Buffer.AppendByte(chars[c>>4])
315 w.Buffer.AppendByte(chars[c&0xf])
324 runeValue, runeWidth := utf8.DecodeRuneInString(s[i:])
325 if runeValue == utf8.RuneError && runeWidth == 1 {
326 w.Buffer.AppendString(s[p:i])
327 w.Buffer.AppendString(`\ufffd`)
333 // jsonp stuff - tab separator and line separator
334 if runeValue == '\u2028' || runeValue == '\u2029' {
335 w.Buffer.AppendString(s[p:i])
336 w.Buffer.AppendString(`\u202`)
337 w.Buffer.AppendByte(chars[runeValue&0xf])
344 w.Buffer.AppendString(s[p:])
345 w.Buffer.AppendByte('"')
348 const encode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
351 func (w *Writer) base64(in []byte) {
357 w.Buffer.EnsureSpace(((len(in)-1)/3 + 1) * 4)
360 n := (len(in) / 3) * 3
363 // Convert 3x 8bit source bytes into 4 bytes
364 val := uint(in[si+0])<<16 | uint(in[si+1])<<8 | uint(in[si+2])
366 w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>18&0x3F], encode[val>>12&0x3F], encode[val>>6&0x3F], encode[val&0x3F])
371 remain := len(in) - si
376 // Add the remaining small block
377 val := uint(in[si+0]) << 16
379 val |= uint(in[si+1]) << 8
382 w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>18&0x3F], encode[val>>12&0x3F])
386 w.Buffer.Buf = append(w.Buffer.Buf, encode[val>>6&0x3F], byte(padChar))
388 w.Buffer.Buf = append(w.Buffer.Buf, byte(padChar), byte(padChar))