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