| | |
| | |
| | |
| |
|
| | |
| |
|
| | package jsontext |
| |
|
| | import ( |
| | "bytes" |
| | "io" |
| | "math/bits" |
| |
|
| | "encoding/json/internal/jsonflags" |
| | "encoding/json/internal/jsonopts" |
| | "encoding/json/internal/jsonwire" |
| | ) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | type Encoder struct { |
| | s encoderState |
| | } |
| |
|
| | |
| | |
| | type encoderState struct { |
| | state |
| | encodeBuffer |
| | jsonopts.Struct |
| |
|
| | SeenPointers map[any]struct{} |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | type encodeBuffer struct { |
| | Buf []byte |
| |
|
| | |
| | |
| | baseOffset int64 |
| |
|
| | wr io.Writer |
| |
|
| | |
| | maxValue int |
| | |
| | availBuffer []byte |
| | |
| | |
| | bufStats bufferStatistics |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func NewEncoder(w io.Writer, opts ...Options) *Encoder { |
| | e := new(Encoder) |
| | e.Reset(w, opts...) |
| | return e |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func (e *Encoder) Reset(w io.Writer, opts ...Options) { |
| | switch { |
| | case e == nil: |
| | panic("jsontext: invalid nil Encoder") |
| | case w == nil: |
| | panic("jsontext: invalid nil io.Writer") |
| | case e.s.Flags.Get(jsonflags.WithinArshalCall): |
| | panic("jsontext: cannot reset Encoder passed to json.MarshalerTo") |
| | } |
| | |
| | b := e.s.Buf[:0] |
| | if _, ok := e.s.wr.(*bytes.Buffer); ok { |
| | b = nil |
| | } |
| | e.s.reset(b, w, opts...) |
| | } |
| |
|
| | func (e *encoderState) reset(b []byte, w io.Writer, opts ...Options) { |
| | e.state.reset() |
| | e.encodeBuffer = encodeBuffer{Buf: b, wr: w, availBuffer: e.availBuffer, bufStats: e.bufStats} |
| | if bb, ok := w.(*bytes.Buffer); ok && bb != nil { |
| | e.Buf = bb.AvailableBuffer() |
| | } |
| | opts2 := jsonopts.Struct{} |
| | opts2.Join(opts...) |
| | e.Struct = opts2 |
| | if e.Flags.Get(jsonflags.Multiline) { |
| | if !e.Flags.Has(jsonflags.SpaceAfterColon) { |
| | e.Flags.Set(jsonflags.SpaceAfterColon | 1) |
| | } |
| | if !e.Flags.Has(jsonflags.SpaceAfterComma) { |
| | e.Flags.Set(jsonflags.SpaceAfterComma | 0) |
| | } |
| | if !e.Flags.Has(jsonflags.Indent) { |
| | e.Flags.Set(jsonflags.Indent | 1) |
| | e.Indent = "\t" |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (e *Encoder) Options() Options { |
| | return &e.s.Struct |
| | } |
| |
|
| | |
| | func (e *encoderState) NeedFlush() bool { |
| | |
| |
|
| | |
| | |
| | |
| | |
| | return e.wr != nil && (e.Tokens.Depth() == 1 || len(e.Buf) > 3*cap(e.Buf)/4) |
| | } |
| |
|
| | |
| | |
| | func (e *encoderState) Flush() error { |
| | if e.wr == nil || e.avoidFlush() { |
| | return nil |
| | } |
| |
|
| | |
| | if e.Tokens.Depth() == 1 && !e.Flags.Get(jsonflags.OmitTopLevelNewline) { |
| | e.Buf = append(e.Buf, '\n') |
| | } |
| |
|
| | |
| | e.Names.copyQuotedBuffer(e.Buf) |
| |
|
| | |
| | if bb, ok := e.wr.(*bytes.Buffer); ok { |
| | |
| | |
| | |
| | |
| | n, _ := bb.Write(e.Buf) |
| | e.baseOffset += int64(n) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | if avail := bb.Available(); avail < bb.Len()/4 { |
| | bb.Grow(avail + 1) |
| | } |
| |
|
| | e.Buf = bb.AvailableBuffer() |
| | return nil |
| | } |
| |
|
| | |
| | n, err := e.wr.Write(e.Buf) |
| | e.baseOffset += int64(n) |
| | if err != nil { |
| | |
| | |
| | |
| | if n > 0 { |
| | e.Buf = e.Buf[:copy(e.Buf, e.Buf[n:])] |
| | } |
| | return &ioError{action: "write", err: err} |
| | } |
| | e.Buf = e.Buf[:0] |
| |
|
| | |
| | |
| | |
| | const maxBufferSize = 4 << 10 |
| | const growthSizeFactor = 2 |
| | const growthRateFactor = 2 |
| | |
| | grow := cap(e.Buf) <= maxBufferSize/growthSizeFactor |
| | |
| | |
| | grow = grow && int64(cap(e.Buf)) < e.previousOffsetEnd()/growthRateFactor |
| | if grow { |
| | e.Buf = make([]byte, 0, cap(e.Buf)*growthSizeFactor) |
| | } |
| |
|
| | return nil |
| | } |
| | func (d *encodeBuffer) offsetAt(pos int) int64 { return d.baseOffset + int64(pos) } |
| | func (e *encodeBuffer) previousOffsetEnd() int64 { return e.baseOffset + int64(len(e.Buf)) } |
| | func (e *encodeBuffer) unflushedBuffer() []byte { return e.Buf } |
| |
|
| | |
| | |
| | func (e *encoderState) avoidFlush() bool { |
| | switch { |
| | case e.Tokens.Last.Length() == 0: |
| | |
| | |
| | return true |
| | case e.Tokens.Last.needObjectValue(): |
| | |
| | |
| | return true |
| | case e.Tokens.Last.NeedObjectName() && len(e.Buf) >= 2: |
| | |
| | switch string(e.Buf[len(e.Buf)-2:]) { |
| | case `ll`, `""`, `{}`, `[]`: |
| | return true |
| | } |
| | } |
| | return false |
| | } |
| |
|
| | |
| | |
| | func (e *encoderState) UnwriteEmptyObjectMember(prevName *string) bool { |
| | if last := e.Tokens.Last; !last.isObject() || !last.NeedObjectName() || last.Length() == 0 { |
| | panic("BUG: must be called on an object after writing a value") |
| | } |
| |
|
| | |
| | |
| | b := e.unflushedBuffer() |
| |
|
| | |
| | var n int |
| | if len(b) >= 3 { |
| | switch string(b[len(b)-2:]) { |
| | case "ll": |
| | n = len(`null`) |
| | case `""`: |
| | |
| | |
| | if b[len(b)-3] == '\\' { |
| | return false |
| | } |
| | n = len(`""`) |
| | case `{}`: |
| | n = len(`{}`) |
| | case `[]`: |
| | n = len(`[]`) |
| | } |
| | } |
| | if n == 0 { |
| | return false |
| | } |
| |
|
| | |
| | b = b[:len(b)-n] |
| | b = jsonwire.TrimSuffixWhitespace(b) |
| | b = jsonwire.TrimSuffixByte(b, ':') |
| | b = jsonwire.TrimSuffixString(b) |
| | b = jsonwire.TrimSuffixWhitespace(b) |
| | b = jsonwire.TrimSuffixByte(b, ',') |
| | e.Buf = b |
| |
|
| | |
| | e.Tokens.Last.decrement() |
| | e.Tokens.Last.decrement() |
| | if !e.Flags.Get(jsonflags.AllowDuplicateNames) { |
| | if e.Tokens.Last.isActiveNamespace() { |
| | e.Namespaces.Last().removeLast() |
| | } |
| | } |
| | e.Names.clearLast() |
| | if prevName != nil { |
| | e.Names.copyQuotedBuffer(e.Buf) |
| | e.Names.replaceLastUnquotedName(*prevName) |
| | } |
| | return true |
| | } |
| |
|
| | |
| | |
| | func (e *encoderState) UnwriteOnlyObjectMemberName() string { |
| | if last := e.Tokens.Last; !last.isObject() || last.Length() != 1 { |
| | panic("BUG: must be called on an object after writing first name") |
| | } |
| |
|
| | |
| | b := jsonwire.TrimSuffixString(e.Buf) |
| | isVerbatim := bytes.IndexByte(e.Buf[len(b):], '\\') < 0 |
| | name := string(jsonwire.UnquoteMayCopy(e.Buf[len(b):], isVerbatim)) |
| | e.Buf = jsonwire.TrimSuffixWhitespace(b) |
| |
|
| | |
| | e.Tokens.Last.decrement() |
| | if !e.Flags.Get(jsonflags.AllowDuplicateNames) { |
| | if e.Tokens.Last.isActiveNamespace() { |
| | e.Namespaces.Last().removeLast() |
| | } |
| | } |
| | e.Names.clearLast() |
| | return name |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (e *Encoder) WriteToken(t Token) error { |
| | return e.s.WriteToken(t) |
| | } |
| | func (e *encoderState) WriteToken(t Token) error { |
| | k := t.Kind() |
| | b := e.Buf |
| |
|
| | |
| | b = e.Tokens.MayAppendDelim(b, k) |
| | if e.Flags.Get(jsonflags.AnyWhitespace) { |
| | b = e.appendWhitespace(b, k) |
| | } |
| | pos := len(b) |
| |
|
| | |
| | var err error |
| | switch k { |
| | case 'n': |
| | b = append(b, "null"...) |
| | err = e.Tokens.appendLiteral() |
| | case 'f': |
| | b = append(b, "false"...) |
| | err = e.Tokens.appendLiteral() |
| | case 't': |
| | b = append(b, "true"...) |
| | err = e.Tokens.appendLiteral() |
| | case '"': |
| | if b, err = t.appendString(b, &e.Flags); err != nil { |
| | break |
| | } |
| | if e.Tokens.Last.NeedObjectName() { |
| | if !e.Flags.Get(jsonflags.AllowDuplicateNames) { |
| | if !e.Tokens.Last.isValidNamespace() { |
| | err = errInvalidNamespace |
| | break |
| | } |
| | if e.Tokens.Last.isActiveNamespace() && !e.Namespaces.Last().insertQuoted(b[pos:], false) { |
| | err = wrapWithObjectName(ErrDuplicateName, b[pos:]) |
| | break |
| | } |
| | } |
| | e.Names.ReplaceLastQuotedOffset(pos) |
| | } |
| | err = e.Tokens.appendString() |
| | case '0': |
| | if b, err = t.appendNumber(b, &e.Flags); err != nil { |
| | break |
| | } |
| | err = e.Tokens.appendNumber() |
| | case '{': |
| | b = append(b, '{') |
| | if err = e.Tokens.pushObject(); err != nil { |
| | break |
| | } |
| | e.Names.push() |
| | if !e.Flags.Get(jsonflags.AllowDuplicateNames) { |
| | e.Namespaces.push() |
| | } |
| | case '}': |
| | b = append(b, '}') |
| | if err = e.Tokens.popObject(); err != nil { |
| | break |
| | } |
| | e.Names.pop() |
| | if !e.Flags.Get(jsonflags.AllowDuplicateNames) { |
| | e.Namespaces.pop() |
| | } |
| | case '[': |
| | b = append(b, '[') |
| | err = e.Tokens.pushArray() |
| | case ']': |
| | b = append(b, ']') |
| | err = e.Tokens.popArray() |
| | default: |
| | err = errInvalidToken |
| | } |
| | if err != nil { |
| | return wrapSyntacticError(e, err, pos, +1) |
| | } |
| |
|
| | |
| | e.Buf = b |
| | if e.NeedFlush() { |
| | return e.Flush() |
| | } |
| | return nil |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (e *encoderState) AppendRaw(k Kind, safeASCII bool, appendFn func([]byte) ([]byte, error)) error { |
| | b := e.Buf |
| |
|
| | |
| | b = e.Tokens.MayAppendDelim(b, k) |
| | if e.Flags.Get(jsonflags.AnyWhitespace) { |
| | b = e.appendWhitespace(b, k) |
| | } |
| | pos := len(b) |
| |
|
| | var err error |
| | switch k { |
| | case '"': |
| | |
| | |
| | b = append(b, '"') |
| | if b, err = appendFn(b); err != nil { |
| | return err |
| | } |
| | b = append(b, '"') |
| |
|
| | |
| | |
| | isVerbatim := safeASCII || !jsonwire.NeedEscape(b[pos+len(`"`):len(b)-len(`"`)]) |
| | if !isVerbatim { |
| | var err error |
| | b2 := append(e.availBuffer, b[pos+len(`"`):len(b)-len(`"`)]...) |
| | b, err = jsonwire.AppendQuote(b[:pos], string(b2), &e.Flags) |
| | e.availBuffer = b2[:0] |
| | if err != nil { |
| | return wrapSyntacticError(e, err, pos, +1) |
| | } |
| | } |
| |
|
| | |
| | if e.Tokens.Last.NeedObjectName() { |
| | if !e.Flags.Get(jsonflags.AllowDuplicateNames) { |
| | if !e.Tokens.Last.isValidNamespace() { |
| | return wrapSyntacticError(e, err, pos, +1) |
| | } |
| | if e.Tokens.Last.isActiveNamespace() && !e.Namespaces.Last().insertQuoted(b[pos:], isVerbatim) { |
| | err = wrapWithObjectName(ErrDuplicateName, b[pos:]) |
| | return wrapSyntacticError(e, err, pos, +1) |
| | } |
| | } |
| | e.Names.ReplaceLastQuotedOffset(pos) |
| | } |
| | if err := e.Tokens.appendString(); err != nil { |
| | return wrapSyntacticError(e, err, pos, +1) |
| | } |
| | case '0': |
| | if b, err = appendFn(b); err != nil { |
| | return err |
| | } |
| | if err := e.Tokens.appendNumber(); err != nil { |
| | return wrapSyntacticError(e, err, pos, +1) |
| | } |
| | default: |
| | panic("BUG: invalid kind") |
| | } |
| |
|
| | |
| | e.Buf = b |
| | if e.NeedFlush() { |
| | return e.Flush() |
| | } |
| | return nil |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (e *Encoder) WriteValue(v Value) error { |
| | return e.s.WriteValue(v) |
| | } |
| | func (e *encoderState) WriteValue(v Value) error { |
| | e.maxValue |= len(v) |
| |
|
| | k := v.Kind() |
| | b := e.Buf |
| |
|
| | |
| | b = e.Tokens.MayAppendDelim(b, k) |
| | if e.Flags.Get(jsonflags.AnyWhitespace) { |
| | b = e.appendWhitespace(b, k) |
| | } |
| | pos := len(b) |
| |
|
| | |
| | var n int |
| | n += jsonwire.ConsumeWhitespace(v[n:]) |
| | b, m, err := e.reformatValue(b, v[n:], e.Tokens.Depth()) |
| | if err != nil { |
| | return wrapSyntacticError(e, err, pos+n+m, +1) |
| | } |
| | n += m |
| | n += jsonwire.ConsumeWhitespace(v[n:]) |
| | if len(v) > n { |
| | err = jsonwire.NewInvalidCharacterError(v[n:], "after top-level value") |
| | return wrapSyntacticError(e, err, pos+n, 0) |
| | } |
| |
|
| | |
| | switch k { |
| | case 'n', 'f', 't': |
| | err = e.Tokens.appendLiteral() |
| | case '"': |
| | if e.Tokens.Last.NeedObjectName() { |
| | if !e.Flags.Get(jsonflags.AllowDuplicateNames) { |
| | if !e.Tokens.Last.isValidNamespace() { |
| | err = errInvalidNamespace |
| | break |
| | } |
| | if e.Tokens.Last.isActiveNamespace() && !e.Namespaces.Last().insertQuoted(b[pos:], false) { |
| | err = wrapWithObjectName(ErrDuplicateName, b[pos:]) |
| | break |
| | } |
| | } |
| | e.Names.ReplaceLastQuotedOffset(pos) |
| | } |
| | err = e.Tokens.appendString() |
| | case '0': |
| | err = e.Tokens.appendNumber() |
| | case '{': |
| | if err = e.Tokens.pushObject(); err != nil { |
| | break |
| | } |
| | if err = e.Tokens.popObject(); err != nil { |
| | panic("BUG: popObject should never fail immediately after pushObject: " + err.Error()) |
| | } |
| | if e.Flags.Get(jsonflags.ReorderRawObjects) { |
| | mustReorderObjects(b[pos:]) |
| | } |
| | case '[': |
| | if err = e.Tokens.pushArray(); err != nil { |
| | break |
| | } |
| | if err = e.Tokens.popArray(); err != nil { |
| | panic("BUG: popArray should never fail immediately after pushArray: " + err.Error()) |
| | } |
| | if e.Flags.Get(jsonflags.ReorderRawObjects) { |
| | mustReorderObjects(b[pos:]) |
| | } |
| | } |
| | if err != nil { |
| | return wrapSyntacticError(e, err, pos, +1) |
| | } |
| |
|
| | |
| | e.Buf = b |
| | if e.NeedFlush() { |
| | return e.Flush() |
| | } |
| | return nil |
| | } |
| |
|
| | |
| | |
| | |
| | func (e *encoderState) CountNextDelimWhitespace() (n int) { |
| | const next = Kind('"') |
| | delim := e.Tokens.needDelim(next) |
| | if delim > 0 { |
| | n += len(",") | len(":") |
| | } |
| | if delim == ':' { |
| | if e.Flags.Get(jsonflags.SpaceAfterColon) { |
| | n += len(" ") |
| | } |
| | } else { |
| | if delim == ',' && e.Flags.Get(jsonflags.SpaceAfterComma) { |
| | n += len(" ") |
| | } |
| | if e.Flags.Get(jsonflags.Multiline) { |
| | if m := e.Tokens.NeedIndent(next); m > 0 { |
| | n += len("\n") + len(e.IndentPrefix) + (m-1)*len(e.Indent) |
| | } |
| | } |
| | } |
| | return n |
| | } |
| |
|
| | |
| | func (e *encoderState) appendWhitespace(b []byte, next Kind) []byte { |
| | if delim := e.Tokens.needDelim(next); delim == ':' { |
| | if e.Flags.Get(jsonflags.SpaceAfterColon) { |
| | b = append(b, ' ') |
| | } |
| | } else { |
| | if delim == ',' && e.Flags.Get(jsonflags.SpaceAfterComma) { |
| | b = append(b, ' ') |
| | } |
| | if e.Flags.Get(jsonflags.Multiline) { |
| | b = e.AppendIndent(b, e.Tokens.NeedIndent(next)) |
| | } |
| | } |
| | return b |
| | } |
| |
|
| | |
| | |
| | func (e *encoderState) AppendIndent(b []byte, n int) []byte { |
| | if n == 0 { |
| | return b |
| | } |
| | b = append(b, '\n') |
| | b = append(b, e.IndentPrefix...) |
| | for ; n > 1; n-- { |
| | b = append(b, e.Indent...) |
| | } |
| | return b |
| | } |
| |
|
| | |
| | |
| | |
| | func (e *encoderState) reformatValue(dst []byte, src Value, depth int) ([]byte, int, error) { |
| | |
| | if len(src) == 0 { |
| | return dst, 0, io.ErrUnexpectedEOF |
| | } |
| | switch k := Kind(src[0]).normalize(); k { |
| | case 'n': |
| | if jsonwire.ConsumeNull(src) == 0 { |
| | n, err := jsonwire.ConsumeLiteral(src, "null") |
| | return dst, n, err |
| | } |
| | return append(dst, "null"...), len("null"), nil |
| | case 'f': |
| | if jsonwire.ConsumeFalse(src) == 0 { |
| | n, err := jsonwire.ConsumeLiteral(src, "false") |
| | return dst, n, err |
| | } |
| | return append(dst, "false"...), len("false"), nil |
| | case 't': |
| | if jsonwire.ConsumeTrue(src) == 0 { |
| | n, err := jsonwire.ConsumeLiteral(src, "true") |
| | return dst, n, err |
| | } |
| | return append(dst, "true"...), len("true"), nil |
| | case '"': |
| | if n := jsonwire.ConsumeSimpleString(src); n > 0 { |
| | dst = append(dst, src[:n]...) |
| | return dst, n, nil |
| | } |
| | return jsonwire.ReformatString(dst, src, &e.Flags) |
| | case '0': |
| | if n := jsonwire.ConsumeSimpleNumber(src); n > 0 && !e.Flags.Get(jsonflags.CanonicalizeNumbers) { |
| | dst = append(dst, src[:n]...) |
| | return dst, n, nil |
| | } |
| | return jsonwire.ReformatNumber(dst, src, &e.Flags) |
| | case '{': |
| | return e.reformatObject(dst, src, depth) |
| | case '[': |
| | return e.reformatArray(dst, src, depth) |
| | default: |
| | return dst, 0, jsonwire.NewInvalidCharacterError(src, "at start of value") |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func (e *encoderState) reformatObject(dst []byte, src Value, depth int) ([]byte, int, error) { |
| | |
| | if len(src) == 0 || src[0] != '{' { |
| | panic("BUG: reformatObject must be called with a buffer that starts with '{'") |
| | } else if depth == maxNestingDepth+1 { |
| | return dst, 0, errMaxDepth |
| | } |
| | dst = append(dst, '{') |
| | n := len("{") |
| |
|
| | |
| | n += jsonwire.ConsumeWhitespace(src[n:]) |
| | if uint(len(src)) <= uint(n) { |
| | return dst, n, io.ErrUnexpectedEOF |
| | } |
| | if src[n] == '}' { |
| | dst = append(dst, '}') |
| | n += len("}") |
| | return dst, n, nil |
| | } |
| |
|
| | var err error |
| | var names *objectNamespace |
| | if !e.Flags.Get(jsonflags.AllowDuplicateNames) { |
| | e.Namespaces.push() |
| | defer e.Namespaces.pop() |
| | names = e.Namespaces.Last() |
| | } |
| | depth++ |
| | for { |
| | |
| | if e.Flags.Get(jsonflags.Multiline) { |
| | dst = e.AppendIndent(dst, depth) |
| | } |
| |
|
| | |
| | n += jsonwire.ConsumeWhitespace(src[n:]) |
| | if uint(len(src)) <= uint(n) { |
| | return dst, n, io.ErrUnexpectedEOF |
| | } |
| | m := jsonwire.ConsumeSimpleString(src[n:]) |
| | isVerbatim := m > 0 |
| | if isVerbatim { |
| | dst = append(dst, src[n:n+m]...) |
| | } else { |
| | dst, m, err = jsonwire.ReformatString(dst, src[n:], &e.Flags) |
| | if err != nil { |
| | return dst, n + m, err |
| | } |
| | } |
| | quotedName := src[n : n+m] |
| | if !e.Flags.Get(jsonflags.AllowDuplicateNames) && !names.insertQuoted(quotedName, isVerbatim) { |
| | return dst, n, wrapWithObjectName(ErrDuplicateName, quotedName) |
| | } |
| | n += m |
| |
|
| | |
| | n += jsonwire.ConsumeWhitespace(src[n:]) |
| | if uint(len(src)) <= uint(n) { |
| | return dst, n, wrapWithObjectName(io.ErrUnexpectedEOF, quotedName) |
| | } |
| | if src[n] != ':' { |
| | err = jsonwire.NewInvalidCharacterError(src[n:], "after object name (expecting ':')") |
| | return dst, n, wrapWithObjectName(err, quotedName) |
| | } |
| | dst = append(dst, ':') |
| | n += len(":") |
| | if e.Flags.Get(jsonflags.SpaceAfterColon) { |
| | dst = append(dst, ' ') |
| | } |
| |
|
| | |
| | n += jsonwire.ConsumeWhitespace(src[n:]) |
| | if uint(len(src)) <= uint(n) { |
| | return dst, n, wrapWithObjectName(io.ErrUnexpectedEOF, quotedName) |
| | } |
| | dst, m, err = e.reformatValue(dst, src[n:], depth) |
| | if err != nil { |
| | return dst, n + m, wrapWithObjectName(err, quotedName) |
| | } |
| | n += m |
| |
|
| | |
| | n += jsonwire.ConsumeWhitespace(src[n:]) |
| | if uint(len(src)) <= uint(n) { |
| | return dst, n, io.ErrUnexpectedEOF |
| | } |
| | switch src[n] { |
| | case ',': |
| | dst = append(dst, ',') |
| | if e.Flags.Get(jsonflags.SpaceAfterComma) { |
| | dst = append(dst, ' ') |
| | } |
| | n += len(",") |
| | continue |
| | case '}': |
| | if e.Flags.Get(jsonflags.Multiline) { |
| | dst = e.AppendIndent(dst, depth-1) |
| | } |
| | dst = append(dst, '}') |
| | n += len("}") |
| | return dst, n, nil |
| | default: |
| | return dst, n, jsonwire.NewInvalidCharacterError(src[n:], "after object value (expecting ',' or '}')") |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func (e *encoderState) reformatArray(dst []byte, src Value, depth int) ([]byte, int, error) { |
| | |
| | if len(src) == 0 || src[0] != '[' { |
| | panic("BUG: reformatArray must be called with a buffer that starts with '['") |
| | } else if depth == maxNestingDepth+1 { |
| | return dst, 0, errMaxDepth |
| | } |
| | dst = append(dst, '[') |
| | n := len("[") |
| |
|
| | |
| | n += jsonwire.ConsumeWhitespace(src[n:]) |
| | if uint(len(src)) <= uint(n) { |
| | return dst, n, io.ErrUnexpectedEOF |
| | } |
| | if src[n] == ']' { |
| | dst = append(dst, ']') |
| | n += len("]") |
| | return dst, n, nil |
| | } |
| |
|
| | var idx int64 |
| | var err error |
| | depth++ |
| | for { |
| | |
| | if e.Flags.Get(jsonflags.Multiline) { |
| | dst = e.AppendIndent(dst, depth) |
| | } |
| |
|
| | |
| | n += jsonwire.ConsumeWhitespace(src[n:]) |
| | if uint(len(src)) <= uint(n) { |
| | return dst, n, io.ErrUnexpectedEOF |
| | } |
| | var m int |
| | dst, m, err = e.reformatValue(dst, src[n:], depth) |
| | if err != nil { |
| | return dst, n + m, wrapWithArrayIndex(err, idx) |
| | } |
| | n += m |
| |
|
| | |
| | n += jsonwire.ConsumeWhitespace(src[n:]) |
| | if uint(len(src)) <= uint(n) { |
| | return dst, n, io.ErrUnexpectedEOF |
| | } |
| | switch src[n] { |
| | case ',': |
| | dst = append(dst, ',') |
| | if e.Flags.Get(jsonflags.SpaceAfterComma) { |
| | dst = append(dst, ' ') |
| | } |
| | n += len(",") |
| | idx++ |
| | continue |
| | case ']': |
| | if e.Flags.Get(jsonflags.Multiline) { |
| | dst = e.AppendIndent(dst, depth-1) |
| | } |
| | dst = append(dst, ']') |
| | n += len("]") |
| | return dst, n, nil |
| | default: |
| | return dst, n, jsonwire.NewInvalidCharacterError(src[n:], "after array value (expecting ',' or ']')") |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func (e *Encoder) OutputOffset() int64 { |
| | return e.s.previousOffsetEnd() |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (e *Encoder) AvailableBuffer() []byte { |
| | |
| | |
| | |
| | |
| | |
| | |
| | n := 1 << bits.Len(uint(e.s.maxValue|63)) |
| | if cap(e.s.availBuffer) < n { |
| | e.s.availBuffer = make([]byte, 0, n) |
| | } |
| | return e.s.availBuffer |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func (e *Encoder) StackDepth() int { |
| | |
| | return e.s.Tokens.Depth() - 1 |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (e *Encoder) StackIndex(i int) (Kind, int64) { |
| | |
| | switch s := e.s.Tokens.index(i); { |
| | case i > 0 && s.isObject(): |
| | return '{', s.Length() |
| | case i > 0 && s.isArray(): |
| | return '[', s.Length() |
| | default: |
| | return 0, s.Length() |
| | } |
| | } |
| |
|
| | |
| | func (e *Encoder) StackPointer() Pointer { |
| | return Pointer(e.s.AppendStackPointer(nil, -1)) |
| | } |
| |
|
| | func (e *encoderState) AppendStackPointer(b []byte, where int) []byte { |
| | e.Names.copyQuotedBuffer(e.Buf) |
| | return e.state.appendStackPointer(b, where) |
| | } |
| |
|