1package jsoniter 2 3import ( 4 "io" 5) 6 7// stream is a io.Writer like object, with JSON specific write functions. 8// Error is not returned as return value, but stored as Error member on this stream instance. 9type Stream struct { 10 cfg *frozenConfig 11 out io.Writer 12 buf []byte 13 Error error 14 indention int 15 Attachment interface{} // open for customized encoder 16} 17 18// NewStream create new stream instance. 19// cfg can be jsoniter.ConfigDefault. 20// out can be nil if write to internal buffer. 21// bufSize is the initial size for the internal buffer in bytes. 22func NewStream(cfg API, out io.Writer, bufSize int) *Stream { 23 return &Stream{ 24 cfg: cfg.(*frozenConfig), 25 out: out, 26 buf: make([]byte, 0, bufSize), 27 Error: nil, 28 indention: 0, 29 } 30} 31 32// Pool returns a pool can provide more stream with same configuration 33func (stream *Stream) Pool() StreamPool { 34 return stream.cfg 35} 36 37// Reset reuse this stream instance by assign a new writer 38func (stream *Stream) Reset(out io.Writer) { 39 stream.out = out 40 stream.buf = stream.buf[:0] 41} 42 43// Available returns how many bytes are unused in the buffer. 44func (stream *Stream) Available() int { 45 return cap(stream.buf) - len(stream.buf) 46} 47 48// Buffered returns the number of bytes that have been written into the current buffer. 49func (stream *Stream) Buffered() int { 50 return len(stream.buf) 51} 52 53// Buffer if writer is nil, use this method to take the result 54func (stream *Stream) Buffer() []byte { 55 return stream.buf 56} 57 58// SetBuffer allows to append to the internal buffer directly 59func (stream *Stream) SetBuffer(buf []byte) { 60 stream.buf = buf 61} 62 63// Write writes the contents of p into the buffer. 64// It returns the number of bytes written. 65// If nn < len(p), it also returns an error explaining 66// why the write is short. 67func (stream *Stream) Write(p []byte) (nn int, err error) { 68 stream.buf = append(stream.buf, p...) 69 if stream.out != nil { 70 nn, err = stream.out.Write(stream.buf) 71 stream.buf = stream.buf[nn:] 72 return 73 } 74 return len(p), nil 75} 76 77// WriteByte writes a single byte. 78func (stream *Stream) writeByte(c byte) { 79 stream.buf = append(stream.buf, c) 80} 81 82func (stream *Stream) writeTwoBytes(c1 byte, c2 byte) { 83 stream.buf = append(stream.buf, c1, c2) 84} 85 86func (stream *Stream) writeThreeBytes(c1 byte, c2 byte, c3 byte) { 87 stream.buf = append(stream.buf, c1, c2, c3) 88} 89 90func (stream *Stream) writeFourBytes(c1 byte, c2 byte, c3 byte, c4 byte) { 91 stream.buf = append(stream.buf, c1, c2, c3, c4) 92} 93 94func (stream *Stream) writeFiveBytes(c1 byte, c2 byte, c3 byte, c4 byte, c5 byte) { 95 stream.buf = append(stream.buf, c1, c2, c3, c4, c5) 96} 97 98// Flush writes any buffered data to the underlying io.Writer. 99func (stream *Stream) Flush() error { 100 if stream.out == nil { 101 return nil 102 } 103 if stream.Error != nil { 104 return stream.Error 105 } 106 _, err := stream.out.Write(stream.buf) 107 if err != nil { 108 if stream.Error == nil { 109 stream.Error = err 110 } 111 return err 112 } 113 stream.buf = stream.buf[:0] 114 return nil 115} 116 117// WriteRaw write string out without quotes, just like []byte 118func (stream *Stream) WriteRaw(s string) { 119 stream.buf = append(stream.buf, s...) 120} 121 122// WriteNil write null to stream 123func (stream *Stream) WriteNil() { 124 stream.writeFourBytes('n', 'u', 'l', 'l') 125} 126 127// WriteTrue write true to stream 128func (stream *Stream) WriteTrue() { 129 stream.writeFourBytes('t', 'r', 'u', 'e') 130} 131 132// WriteFalse write false to stream 133func (stream *Stream) WriteFalse() { 134 stream.writeFiveBytes('f', 'a', 'l', 's', 'e') 135} 136 137// WriteBool write true or false into stream 138func (stream *Stream) WriteBool(val bool) { 139 if val { 140 stream.WriteTrue() 141 } else { 142 stream.WriteFalse() 143 } 144} 145 146// WriteObjectStart write { with possible indention 147func (stream *Stream) WriteObjectStart() { 148 stream.indention += stream.cfg.indentionStep 149 stream.writeByte('{') 150 stream.writeIndention(0) 151} 152 153// WriteObjectField write "field": with possible indention 154func (stream *Stream) WriteObjectField(field string) { 155 stream.WriteString(field) 156 if stream.indention > 0 { 157 stream.writeTwoBytes(':', ' ') 158 } else { 159 stream.writeByte(':') 160 } 161} 162 163// WriteObjectEnd write } with possible indention 164func (stream *Stream) WriteObjectEnd() { 165 stream.writeIndention(stream.cfg.indentionStep) 166 stream.indention -= stream.cfg.indentionStep 167 stream.writeByte('}') 168} 169 170// WriteEmptyObject write {} 171func (stream *Stream) WriteEmptyObject() { 172 stream.writeByte('{') 173 stream.writeByte('}') 174} 175 176// WriteMore write , with possible indention 177func (stream *Stream) WriteMore() { 178 stream.writeByte(',') 179 stream.writeIndention(0) 180} 181 182// WriteArrayStart write [ with possible indention 183func (stream *Stream) WriteArrayStart() { 184 stream.indention += stream.cfg.indentionStep 185 stream.writeByte('[') 186 stream.writeIndention(0) 187} 188 189// WriteEmptyArray write [] 190func (stream *Stream) WriteEmptyArray() { 191 stream.writeTwoBytes('[', ']') 192} 193 194// WriteArrayEnd write ] with possible indention 195func (stream *Stream) WriteArrayEnd() { 196 stream.writeIndention(stream.cfg.indentionStep) 197 stream.indention -= stream.cfg.indentionStep 198 stream.writeByte(']') 199} 200 201func (stream *Stream) writeIndention(delta int) { 202 if stream.indention == 0 { 203 return 204 } 205 stream.writeByte('\n') 206 toWrite := stream.indention - delta 207 for i := 0; i < toWrite; i++ { 208 stream.buf = append(stream.buf, ' ') 209 } 210} 211