gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

indent.go (5164B)


      1 package encoder
      2 
      3 import (
      4 	"bytes"
      5 	"fmt"
      6 
      7 	"github.com/goccy/go-json/internal/errors"
      8 )
      9 
     10 func takeIndentSrcRuntimeContext(src []byte) (*RuntimeContext, []byte) {
     11 	ctx := TakeRuntimeContext()
     12 	buf := ctx.Buf[:0]
     13 	buf = append(append(buf, src...), nul)
     14 	ctx.Buf = buf
     15 	return ctx, buf
     16 }
     17 
     18 func Indent(buf *bytes.Buffer, src []byte, prefix, indentStr string) error {
     19 	if len(src) == 0 {
     20 		return errors.ErrUnexpectedEndOfJSON("", 0)
     21 	}
     22 
     23 	srcCtx, srcBuf := takeIndentSrcRuntimeContext(src)
     24 	dstCtx := TakeRuntimeContext()
     25 	dst := dstCtx.Buf[:0]
     26 
     27 	dst, err := indentAndWrite(buf, dst, srcBuf, prefix, indentStr)
     28 	if err != nil {
     29 		ReleaseRuntimeContext(srcCtx)
     30 		ReleaseRuntimeContext(dstCtx)
     31 		return err
     32 	}
     33 	dstCtx.Buf = dst
     34 	ReleaseRuntimeContext(srcCtx)
     35 	ReleaseRuntimeContext(dstCtx)
     36 	return nil
     37 }
     38 
     39 func indentAndWrite(buf *bytes.Buffer, dst []byte, src []byte, prefix, indentStr string) ([]byte, error) {
     40 	dst, err := doIndent(dst, src, prefix, indentStr, false)
     41 	if err != nil {
     42 		return nil, err
     43 	}
     44 	if _, err := buf.Write(dst); err != nil {
     45 		return nil, err
     46 	}
     47 	return dst, nil
     48 }
     49 
     50 func doIndent(dst, src []byte, prefix, indentStr string, escape bool) ([]byte, error) {
     51 	buf, cursor, err := indentValue(dst, src, 0, 0, []byte(prefix), []byte(indentStr), escape)
     52 	if err != nil {
     53 		return nil, err
     54 	}
     55 	if err := validateEndBuf(src, cursor); err != nil {
     56 		return nil, err
     57 	}
     58 	return buf, nil
     59 }
     60 
     61 func indentValue(
     62 	dst []byte,
     63 	src []byte,
     64 	indentNum int,
     65 	cursor int64,
     66 	prefix []byte,
     67 	indentBytes []byte,
     68 	escape bool) ([]byte, int64, error) {
     69 	for {
     70 		switch src[cursor] {
     71 		case ' ', '\t', '\n', '\r':
     72 			cursor++
     73 			continue
     74 		case '{':
     75 			return indentObject(dst, src, indentNum, cursor, prefix, indentBytes, escape)
     76 		case '}':
     77 			return nil, 0, errors.ErrSyntax("unexpected character '}'", cursor)
     78 		case '[':
     79 			return indentArray(dst, src, indentNum, cursor, prefix, indentBytes, escape)
     80 		case ']':
     81 			return nil, 0, errors.ErrSyntax("unexpected character ']'", cursor)
     82 		case '"':
     83 			return compactString(dst, src, cursor, escape)
     84 		case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
     85 			return compactNumber(dst, src, cursor)
     86 		case 't':
     87 			return compactTrue(dst, src, cursor)
     88 		case 'f':
     89 			return compactFalse(dst, src, cursor)
     90 		case 'n':
     91 			return compactNull(dst, src, cursor)
     92 		default:
     93 			return nil, 0, errors.ErrSyntax(fmt.Sprintf("unexpected character '%c'", src[cursor]), cursor)
     94 		}
     95 	}
     96 }
     97 
     98 func indentObject(
     99 	dst []byte,
    100 	src []byte,
    101 	indentNum int,
    102 	cursor int64,
    103 	prefix []byte,
    104 	indentBytes []byte,
    105 	escape bool) ([]byte, int64, error) {
    106 	if src[cursor] == '{' {
    107 		dst = append(dst, '{')
    108 	} else {
    109 		return nil, 0, errors.ErrExpected("expected { character for object value", cursor)
    110 	}
    111 	cursor = skipWhiteSpace(src, cursor+1)
    112 	if src[cursor] == '}' {
    113 		dst = append(dst, '}')
    114 		return dst, cursor + 1, nil
    115 	}
    116 	indentNum++
    117 	var err error
    118 	for {
    119 		dst = append(append(dst, '\n'), prefix...)
    120 		for i := 0; i < indentNum; i++ {
    121 			dst = append(dst, indentBytes...)
    122 		}
    123 		cursor = skipWhiteSpace(src, cursor)
    124 		dst, cursor, err = compactString(dst, src, cursor, escape)
    125 		if err != nil {
    126 			return nil, 0, err
    127 		}
    128 		cursor = skipWhiteSpace(src, cursor)
    129 		if src[cursor] != ':' {
    130 			return nil, 0, errors.ErrSyntax(
    131 				fmt.Sprintf("invalid character '%c' after object key", src[cursor]),
    132 				cursor+1,
    133 			)
    134 		}
    135 		dst = append(dst, ':', ' ')
    136 		dst, cursor, err = indentValue(dst, src, indentNum, cursor+1, prefix, indentBytes, escape)
    137 		if err != nil {
    138 			return nil, 0, err
    139 		}
    140 		cursor = skipWhiteSpace(src, cursor)
    141 		switch src[cursor] {
    142 		case '}':
    143 			dst = append(append(dst, '\n'), prefix...)
    144 			for i := 0; i < indentNum-1; i++ {
    145 				dst = append(dst, indentBytes...)
    146 			}
    147 			dst = append(dst, '}')
    148 			cursor++
    149 			return dst, cursor, nil
    150 		case ',':
    151 			dst = append(dst, ',')
    152 		default:
    153 			return nil, 0, errors.ErrSyntax(
    154 				fmt.Sprintf("invalid character '%c' after object key:value pair", src[cursor]),
    155 				cursor+1,
    156 			)
    157 		}
    158 		cursor++
    159 	}
    160 }
    161 
    162 func indentArray(
    163 	dst []byte,
    164 	src []byte,
    165 	indentNum int,
    166 	cursor int64,
    167 	prefix []byte,
    168 	indentBytes []byte,
    169 	escape bool) ([]byte, int64, error) {
    170 	if src[cursor] == '[' {
    171 		dst = append(dst, '[')
    172 	} else {
    173 		return nil, 0, errors.ErrExpected("expected [ character for array value", cursor)
    174 	}
    175 	cursor = skipWhiteSpace(src, cursor+1)
    176 	if src[cursor] == ']' {
    177 		dst = append(dst, ']')
    178 		return dst, cursor + 1, nil
    179 	}
    180 	indentNum++
    181 	var err error
    182 	for {
    183 		dst = append(append(dst, '\n'), prefix...)
    184 		for i := 0; i < indentNum; i++ {
    185 			dst = append(dst, indentBytes...)
    186 		}
    187 		dst, cursor, err = indentValue(dst, src, indentNum, cursor, prefix, indentBytes, escape)
    188 		if err != nil {
    189 			return nil, 0, err
    190 		}
    191 		cursor = skipWhiteSpace(src, cursor)
    192 		switch src[cursor] {
    193 		case ']':
    194 			dst = append(append(dst, '\n'), prefix...)
    195 			for i := 0; i < indentNum-1; i++ {
    196 				dst = append(dst, indentBytes...)
    197 			}
    198 			dst = append(dst, ']')
    199 			cursor++
    200 			return dst, cursor, nil
    201 		case ',':
    202 			dst = append(dst, ',')
    203 		default:
    204 			return nil, 0, errors.ErrSyntax(
    205 				fmt.Sprintf("invalid character '%c' after array value", src[cursor]),
    206 				cursor+1,
    207 			)
    208 		}
    209 		cursor++
    210 	}
    211 }