mirror of
https://github.com/json-iterator/go.git
synced 2024-11-24 08:22:14 +02:00
309 lines
5.9 KiB
Go
309 lines
5.9 KiB
Go
package jsoniter
|
|
|
|
import (
|
|
"io"
|
|
)
|
|
|
|
type Stream struct {
|
|
out io.Writer
|
|
buf []byte
|
|
n int
|
|
Error error
|
|
indention int
|
|
IndentionStep int
|
|
}
|
|
|
|
func NewStream(out io.Writer, bufSize int) *Stream {
|
|
return &Stream{out, make([]byte, bufSize), 0, nil, 0, 0}
|
|
}
|
|
|
|
|
|
// Available returns how many bytes are unused in the buffer.
|
|
func (b *Stream) Available() int {
|
|
return len(b.buf) - b.n
|
|
}
|
|
|
|
// Buffered returns the number of bytes that have been written into the current buffer.
|
|
func (b *Stream) Buffered() int {
|
|
return b.n
|
|
}
|
|
|
|
// Write writes the contents of p into the buffer.
|
|
// It returns the number of bytes written.
|
|
// If nn < len(p), it also returns an error explaining
|
|
// why the write is short.
|
|
func (b *Stream) Write(p []byte) (nn int, err error) {
|
|
for len(p) > b.Available() && b.Error == nil {
|
|
var n int
|
|
if b.Buffered() == 0 {
|
|
// Large write, empty buffer.
|
|
// Write directly from p to avoid copy.
|
|
n, b.Error = b.out.Write(p)
|
|
} else {
|
|
n = copy(b.buf[b.n:], p)
|
|
b.n += n
|
|
b.Flush()
|
|
}
|
|
nn += n
|
|
p = p[n:]
|
|
}
|
|
if b.Error != nil {
|
|
return nn, b.Error
|
|
}
|
|
n := copy(b.buf[b.n:], p)
|
|
b.n += n
|
|
nn += n
|
|
return nn, nil
|
|
}
|
|
|
|
|
|
// WriteByte writes a single byte.
|
|
func (b *Stream) writeByte(c byte) {
|
|
if b.Error != nil {
|
|
return
|
|
}
|
|
if b.Available() <= 0 && b.Flush() != nil {
|
|
return
|
|
}
|
|
b.buf[b.n] = c
|
|
b.n++
|
|
}
|
|
|
|
func (b *Stream) writeTwoBytes(c1 byte, c2 byte) {
|
|
if b.Error != nil {
|
|
return
|
|
}
|
|
if b.Available() <= 1 && b.Flush() != nil {
|
|
return
|
|
}
|
|
b.buf[b.n] = c1
|
|
b.buf[b.n + 1] = c2
|
|
b.n += 2
|
|
}
|
|
|
|
func (b *Stream) writeThreeBytes(c1 byte, c2 byte, c3 byte) {
|
|
if b.Error != nil {
|
|
return
|
|
}
|
|
if b.Available() <= 2 && b.Flush() != nil {
|
|
return
|
|
}
|
|
b.buf[b.n] = c1
|
|
b.buf[b.n + 1] = c2
|
|
b.buf[b.n + 2] = c3
|
|
b.n += 3
|
|
}
|
|
|
|
func (b *Stream) writeFourBytes(c1 byte, c2 byte, c3 byte, c4 byte) {
|
|
if b.Error != nil {
|
|
return
|
|
}
|
|
if b.Available() <= 3 && b.Flush() != nil {
|
|
return
|
|
}
|
|
b.buf[b.n] = c1
|
|
b.buf[b.n + 1] = c2
|
|
b.buf[b.n + 2] = c3
|
|
b.buf[b.n + 3] = c4
|
|
b.n += 4
|
|
}
|
|
|
|
func (b *Stream) writeFiveBytes(c1 byte, c2 byte, c3 byte, c4 byte, c5 byte) {
|
|
if b.Error != nil {
|
|
return
|
|
}
|
|
if b.Available() <= 3 && b.Flush() != nil {
|
|
return
|
|
}
|
|
b.buf[b.n] = c1
|
|
b.buf[b.n + 1] = c2
|
|
b.buf[b.n + 2] = c3
|
|
b.buf[b.n + 3] = c4
|
|
b.buf[b.n + 4] = c5
|
|
b.n += 5
|
|
}
|
|
|
|
// Flush writes any buffered data to the underlying io.Writer.
|
|
func (b *Stream) Flush() error {
|
|
if b.Error != nil {
|
|
return b.Error
|
|
}
|
|
if b.n == 0 {
|
|
return nil
|
|
}
|
|
n, err := b.out.Write(b.buf[0:b.n])
|
|
if n < b.n && err == nil {
|
|
err = io.ErrShortWrite
|
|
}
|
|
if err != nil {
|
|
if n > 0 && n < b.n {
|
|
copy(b.buf[0:b.n - n], b.buf[n:b.n])
|
|
}
|
|
b.n -= n
|
|
b.Error = err
|
|
return err
|
|
}
|
|
b.n = 0
|
|
return nil
|
|
}
|
|
|
|
func (b *Stream) WriteRaw(s string) {
|
|
for len(s) > b.Available() && b.Error == nil {
|
|
n := copy(b.buf[b.n:], s)
|
|
b.n += n
|
|
s = s[n:]
|
|
b.Flush()
|
|
}
|
|
if b.Error != nil {
|
|
return
|
|
}
|
|
n := copy(b.buf[b.n:], s)
|
|
b.n += n
|
|
}
|
|
|
|
func (stream *Stream) WriteString(s string) {
|
|
valLen := len(s)
|
|
toWriteLen := valLen
|
|
bufLengthMinusTwo := len(stream.buf) - 2 // make room for the quotes
|
|
if stream.n + toWriteLen > bufLengthMinusTwo {
|
|
toWriteLen = bufLengthMinusTwo - stream.n
|
|
}
|
|
if toWriteLen < 0 {
|
|
stream.Flush()
|
|
if stream.n + toWriteLen > bufLengthMinusTwo {
|
|
toWriteLen = bufLengthMinusTwo - stream.n
|
|
}
|
|
}
|
|
n := stream.n
|
|
stream.buf[n] = '"'
|
|
n++
|
|
// write string, the fast path, without utf8 and escape support
|
|
i := 0
|
|
for ; i < toWriteLen; i++ {
|
|
c := s[i]
|
|
if c > 31 && c != '"' && c != '\\' {
|
|
stream.buf[n] = c
|
|
n++
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if i == valLen {
|
|
stream.buf[n] = '"'
|
|
n++
|
|
stream.n = n
|
|
return
|
|
}
|
|
stream.n = n
|
|
// for the remaining parts, we process them char by char
|
|
stream.writeStringSlowPath(s, i, valLen);
|
|
stream.writeByte('"')
|
|
}
|
|
|
|
func (stream *Stream) writeStringSlowPath(s string, i int, valLen int) {
|
|
for ; i < valLen; i++ {
|
|
c := s[i]
|
|
switch (c) {
|
|
case '"':
|
|
stream.writeTwoBytes('\\', '"')
|
|
case '\\':
|
|
stream.writeTwoBytes('\\', '\\')
|
|
case '\b':
|
|
stream.writeTwoBytes('\\', 'b')
|
|
case '\f':
|
|
stream.writeTwoBytes('\\', 'f')
|
|
case '\n':
|
|
stream.writeTwoBytes('\\', 'n')
|
|
case '\r':
|
|
stream.writeTwoBytes('\\', 'r')
|
|
case '\t':
|
|
stream.writeTwoBytes('\\', 't')
|
|
default:
|
|
stream.writeByte(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
func (stream *Stream) WriteNil() {
|
|
stream.writeFourBytes('n', 'u', 'l', 'l')
|
|
}
|
|
|
|
func (stream *Stream) WriteTrue() {
|
|
stream.writeFourBytes('t', 'r', 'u', 'e')
|
|
}
|
|
|
|
func (stream *Stream) WriteFalse() {
|
|
stream.writeFiveBytes('f', 'a', 'l', 's', 'e')
|
|
}
|
|
|
|
func (stream *Stream) WriteBool(val bool) {
|
|
if val {
|
|
stream.WriteTrue()
|
|
} else {
|
|
stream.WriteFalse()
|
|
}
|
|
}
|
|
|
|
func (stream *Stream) WriteObjectStart() {
|
|
stream.indention += stream.IndentionStep
|
|
stream.writeByte('{')
|
|
stream.writeIndention(0)
|
|
}
|
|
|
|
func (stream *Stream) WriteObjectField(field string) {
|
|
stream.WriteString(field)
|
|
stream.writeByte(':')
|
|
}
|
|
|
|
func (stream *Stream) WriteObjectEnd() {
|
|
stream.writeIndention(stream.IndentionStep)
|
|
stream.indention -= stream.IndentionStep
|
|
stream.writeByte('}')
|
|
}
|
|
|
|
func (stream *Stream) WriteEmptyObject() {
|
|
stream.writeByte('{')
|
|
stream.writeByte('}')
|
|
}
|
|
|
|
func (stream *Stream) WriteMore() {
|
|
stream.writeByte(',')
|
|
stream.writeIndention(0)
|
|
}
|
|
|
|
func (stream *Stream) WriteArrayStart() {
|
|
stream.indention += stream.IndentionStep
|
|
stream.writeByte('[')
|
|
stream.writeIndention(0)
|
|
}
|
|
|
|
func (stream *Stream) WriteEmptyArray() {
|
|
stream.writeByte('[')
|
|
stream.writeByte(']')
|
|
}
|
|
|
|
func (stream *Stream) WriteArrayEnd() {
|
|
stream.writeIndention(stream.IndentionStep)
|
|
stream.indention -= stream.IndentionStep
|
|
stream.writeByte(']')
|
|
}
|
|
|
|
func (stream *Stream) writeIndention(delta int) {
|
|
if (stream.indention == 0) {
|
|
return
|
|
}
|
|
stream.writeByte('\n')
|
|
toWrite := stream.indention - delta
|
|
i := 0
|
|
for {
|
|
for ; i < toWrite && stream.n < len(stream.buf); i++ {
|
|
stream.buf[stream.n] = ' '
|
|
stream.n ++
|
|
}
|
|
if i == toWrite {
|
|
break;
|
|
} else {
|
|
stream.Flush()
|
|
}
|
|
}
|
|
} |