123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596 |
- package encoder
- import (
- "bytes"
- "encoding"
- "encoding/base64"
- "encoding/json"
- "fmt"
- "math"
- "reflect"
- "strconv"
- "strings"
- "sync"
- "unsafe"
- "github.com/goccy/go-json/internal/errors"
- "github.com/goccy/go-json/internal/runtime"
- )
- func (t OpType) IsMultipleOpHead() bool {
- switch t {
- case OpStructHead:
- return true
- case OpStructHeadSlice:
- return true
- case OpStructHeadArray:
- return true
- case OpStructHeadMap:
- return true
- case OpStructHeadStruct:
- return true
- case OpStructHeadOmitEmpty:
- return true
- case OpStructHeadOmitEmptySlice:
- return true
- case OpStructHeadOmitEmptyArray:
- return true
- case OpStructHeadOmitEmptyMap:
- return true
- case OpStructHeadOmitEmptyStruct:
- return true
- case OpStructHeadSlicePtr:
- return true
- case OpStructHeadOmitEmptySlicePtr:
- return true
- case OpStructHeadArrayPtr:
- return true
- case OpStructHeadOmitEmptyArrayPtr:
- return true
- case OpStructHeadMapPtr:
- return true
- case OpStructHeadOmitEmptyMapPtr:
- return true
- }
- return false
- }
- func (t OpType) IsMultipleOpField() bool {
- switch t {
- case OpStructField:
- return true
- case OpStructFieldSlice:
- return true
- case OpStructFieldArray:
- return true
- case OpStructFieldMap:
- return true
- case OpStructFieldStruct:
- return true
- case OpStructFieldOmitEmpty:
- return true
- case OpStructFieldOmitEmptySlice:
- return true
- case OpStructFieldOmitEmptyArray:
- return true
- case OpStructFieldOmitEmptyMap:
- return true
- case OpStructFieldOmitEmptyStruct:
- return true
- case OpStructFieldSlicePtr:
- return true
- case OpStructFieldOmitEmptySlicePtr:
- return true
- case OpStructFieldArrayPtr:
- return true
- case OpStructFieldOmitEmptyArrayPtr:
- return true
- case OpStructFieldMapPtr:
- return true
- case OpStructFieldOmitEmptyMapPtr:
- return true
- }
- return false
- }
- type OpcodeSet struct {
- Type *runtime.Type
- NoescapeKeyCode *Opcode
- EscapeKeyCode *Opcode
- InterfaceNoescapeKeyCode *Opcode
- InterfaceEscapeKeyCode *Opcode
- CodeLength int
- EndCode *Opcode
- Code Code
- QueryCache map[string]*OpcodeSet
- cacheMu sync.RWMutex
- }
- func (s *OpcodeSet) getQueryCache(hash string) *OpcodeSet {
- s.cacheMu.RLock()
- codeSet := s.QueryCache[hash]
- s.cacheMu.RUnlock()
- return codeSet
- }
- func (s *OpcodeSet) setQueryCache(hash string, codeSet *OpcodeSet) {
- s.cacheMu.Lock()
- s.QueryCache[hash] = codeSet
- s.cacheMu.Unlock()
- }
- type CompiledCode struct {
- Code *Opcode
- Linked bool
- CurLen uintptr
- NextLen uintptr
- }
- const StartDetectingCyclesAfter = 1000
- func Load(base uintptr, idx uintptr) uintptr {
- addr := base + idx
- return **(**uintptr)(unsafe.Pointer(&addr))
- }
- func Store(base uintptr, idx uintptr, p uintptr) {
- addr := base + idx
- **(**uintptr)(unsafe.Pointer(&addr)) = p
- }
- func LoadNPtr(base uintptr, idx uintptr, ptrNum int) uintptr {
- addr := base + idx
- p := **(**uintptr)(unsafe.Pointer(&addr))
- if p == 0 {
- return 0
- }
- return PtrToPtr(p)
-
- }
- func PtrToUint64(p uintptr) uint64 { return **(**uint64)(unsafe.Pointer(&p)) }
- func PtrToFloat32(p uintptr) float32 { return **(**float32)(unsafe.Pointer(&p)) }
- func PtrToFloat64(p uintptr) float64 { return **(**float64)(unsafe.Pointer(&p)) }
- func PtrToBool(p uintptr) bool { return **(**bool)(unsafe.Pointer(&p)) }
- func PtrToBytes(p uintptr) []byte { return **(**[]byte)(unsafe.Pointer(&p)) }
- func PtrToNumber(p uintptr) json.Number { return **(**json.Number)(unsafe.Pointer(&p)) }
- func PtrToString(p uintptr) string { return **(**string)(unsafe.Pointer(&p)) }
- func PtrToSlice(p uintptr) *runtime.SliceHeader { return *(**runtime.SliceHeader)(unsafe.Pointer(&p)) }
- func PtrToPtr(p uintptr) uintptr {
- return uintptr(**(**unsafe.Pointer)(unsafe.Pointer(&p)))
- }
- func PtrToNPtr(p uintptr, ptrNum int) uintptr {
- for i := 0; i < ptrNum; i++ {
- if p == 0 {
- return 0
- }
- p = PtrToPtr(p)
- }
- return p
- }
- func PtrToUnsafePtr(p uintptr) unsafe.Pointer {
- return *(*unsafe.Pointer)(unsafe.Pointer(&p))
- }
- func PtrToInterface(code *Opcode, p uintptr) interface{} {
- return *(*interface{})(unsafe.Pointer(&emptyInterface{
- typ: code.Type,
- ptr: *(*unsafe.Pointer)(unsafe.Pointer(&p)),
- }))
- }
- func ErrUnsupportedValue(code *Opcode, ptr uintptr) *errors.UnsupportedValueError {
- v := *(*interface{})(unsafe.Pointer(&emptyInterface{
- typ: code.Type,
- ptr: *(*unsafe.Pointer)(unsafe.Pointer(&ptr)),
- }))
- return &errors.UnsupportedValueError{
- Value: reflect.ValueOf(v),
- Str: fmt.Sprintf("encountered a cycle via %s", code.Type),
- }
- }
- func ErrUnsupportedFloat(v float64) *errors.UnsupportedValueError {
- return &errors.UnsupportedValueError{
- Value: reflect.ValueOf(v),
- Str: strconv.FormatFloat(v, 'g', -1, 64),
- }
- }
- func ErrMarshalerWithCode(code *Opcode, err error) *errors.MarshalerError {
- return &errors.MarshalerError{
- Type: runtime.RType2Type(code.Type),
- Err: err,
- }
- }
- type emptyInterface struct {
- typ *runtime.Type
- ptr unsafe.Pointer
- }
- type MapItem struct {
- Key []byte
- Value []byte
- }
- type Mapslice struct {
- Items []MapItem
- }
- func (m *Mapslice) Len() int {
- return len(m.Items)
- }
- func (m *Mapslice) Less(i, j int) bool {
- return bytes.Compare(m.Items[i].Key, m.Items[j].Key) < 0
- }
- func (m *Mapslice) Swap(i, j int) {
- m.Items[i], m.Items[j] = m.Items[j], m.Items[i]
- }
- type mapIter struct {
- key unsafe.Pointer
- elem unsafe.Pointer
- t unsafe.Pointer
- h unsafe.Pointer
- buckets unsafe.Pointer
- bptr unsafe.Pointer
- overflow unsafe.Pointer
- oldoverflow unsafe.Pointer
- startBucket uintptr
- offset uint8
- wrapped bool
- B uint8
- i uint8
- bucket uintptr
- checkBucket uintptr
- }
- type MapContext struct {
- Start int
- First int
- Idx int
- Slice *Mapslice
- Buf []byte
- Len int
- Iter mapIter
- }
- var mapContextPool = sync.Pool{
- New: func() interface{} {
- return &MapContext{
- Slice: &Mapslice{},
- }
- },
- }
- func NewMapContext(mapLen int, unorderedMap bool) *MapContext {
- ctx := mapContextPool.Get().(*MapContext)
- if !unorderedMap {
- if len(ctx.Slice.Items) < mapLen {
- ctx.Slice.Items = make([]MapItem, mapLen)
- } else {
- ctx.Slice.Items = ctx.Slice.Items[:mapLen]
- }
- }
- ctx.Buf = ctx.Buf[:0]
- ctx.Iter = mapIter{}
- ctx.Idx = 0
- ctx.Len = mapLen
- return ctx
- }
- func ReleaseMapContext(c *MapContext) {
- mapContextPool.Put(c)
- }
- func MapIterInit(mapType *runtime.Type, m unsafe.Pointer, it *mapIter)
- func MapIterKey(it *mapIter) unsafe.Pointer
- func MapIterNext(it *mapIter)
- func MapLen(m unsafe.Pointer) int
- func AppendByteSlice(_ *RuntimeContext, b []byte, src []byte) []byte {
- if src == nil {
- return append(b, `null`...)
- }
- encodedLen := base64.StdEncoding.EncodedLen(len(src))
- b = append(b, '"')
- pos := len(b)
- remainLen := cap(b[pos:])
- var buf []byte
- if remainLen > encodedLen {
- buf = b[pos : pos+encodedLen]
- } else {
- buf = make([]byte, encodedLen)
- }
- base64.StdEncoding.Encode(buf, src)
- return append(append(b, buf...), '"')
- }
- func AppendFloat32(_ *RuntimeContext, b []byte, v float32) []byte {
- f64 := float64(v)
- abs := math.Abs(f64)
- fmt := byte('f')
-
- if abs != 0 {
- f32 := float32(abs)
- if f32 < 1e-6 || f32 >= 1e21 {
- fmt = 'e'
- }
- }
- return strconv.AppendFloat(b, f64, fmt, -1, 32)
- }
- func AppendFloat64(_ *RuntimeContext, b []byte, v float64) []byte {
- abs := math.Abs(v)
- fmt := byte('f')
-
- if abs != 0 {
- if abs < 1e-6 || abs >= 1e21 {
- fmt = 'e'
- }
- }
- return strconv.AppendFloat(b, v, fmt, -1, 64)
- }
- func AppendBool(_ *RuntimeContext, b []byte, v bool) []byte {
- if v {
- return append(b, "true"...)
- }
- return append(b, "false"...)
- }
- var (
- floatTable = [256]bool{
- '0': true,
- '1': true,
- '2': true,
- '3': true,
- '4': true,
- '5': true,
- '6': true,
- '7': true,
- '8': true,
- '9': true,
- '.': true,
- 'e': true,
- 'E': true,
- '+': true,
- '-': true,
- }
- )
- func AppendNumber(_ *RuntimeContext, b []byte, n json.Number) ([]byte, error) {
- if len(n) == 0 {
- return append(b, '0'), nil
- }
- for i := 0; i < len(n); i++ {
- if !floatTable[n[i]] {
- return nil, fmt.Errorf("json: invalid number literal %q", n)
- }
- }
- b = append(b, n...)
- return b, nil
- }
- func AppendMarshalJSON(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) {
- rv := reflect.ValueOf(v)
- if (code.Flags & AddrForMarshalerFlags) != 0 {
- if rv.CanAddr() {
- rv = rv.Addr()
- } else {
- newV := reflect.New(rv.Type())
- newV.Elem().Set(rv)
- rv = newV
- }
- }
- v = rv.Interface()
- var bb []byte
- if (code.Flags & MarshalerContextFlags) != 0 {
- marshaler, ok := v.(marshalerContext)
- if !ok {
- return AppendNull(ctx, b), nil
- }
- stdctx := ctx.Option.Context
- if ctx.Option.Flag&FieldQueryOption != 0 {
- stdctx = SetFieldQueryToContext(stdctx, code.FieldQuery)
- }
- b, err := marshaler.MarshalJSON(stdctx)
- if err != nil {
- return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
- }
- bb = b
- } else {
- marshaler, ok := v.(json.Marshaler)
- if !ok {
- return AppendNull(ctx, b), nil
- }
- b, err := marshaler.MarshalJSON()
- if err != nil {
- return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
- }
- bb = b
- }
- marshalBuf := ctx.MarshalBuf[:0]
- marshalBuf = append(append(marshalBuf, bb...), nul)
- compactedBuf, err := compact(b, marshalBuf, (ctx.Option.Flag&HTMLEscapeOption) != 0)
- if err != nil {
- return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
- }
- ctx.MarshalBuf = marshalBuf
- return compactedBuf, nil
- }
- func AppendMarshalJSONIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) {
- rv := reflect.ValueOf(v)
- if (code.Flags & AddrForMarshalerFlags) != 0 {
- if rv.CanAddr() {
- rv = rv.Addr()
- } else {
- newV := reflect.New(rv.Type())
- newV.Elem().Set(rv)
- rv = newV
- }
- }
- v = rv.Interface()
- var bb []byte
- if (code.Flags & MarshalerContextFlags) != 0 {
- marshaler, ok := v.(marshalerContext)
- if !ok {
- return AppendNull(ctx, b), nil
- }
- b, err := marshaler.MarshalJSON(ctx.Option.Context)
- if err != nil {
- return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
- }
- bb = b
- } else {
- marshaler, ok := v.(json.Marshaler)
- if !ok {
- return AppendNull(ctx, b), nil
- }
- b, err := marshaler.MarshalJSON()
- if err != nil {
- return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
- }
- bb = b
- }
- marshalBuf := ctx.MarshalBuf[:0]
- marshalBuf = append(append(marshalBuf, bb...), nul)
- indentedBuf, err := doIndent(
- b,
- marshalBuf,
- string(ctx.Prefix)+strings.Repeat(string(ctx.IndentStr), int(ctx.BaseIndent+code.Indent)),
- string(ctx.IndentStr),
- (ctx.Option.Flag&HTMLEscapeOption) != 0,
- )
- if err != nil {
- return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
- }
- ctx.MarshalBuf = marshalBuf
- return indentedBuf, nil
- }
- func AppendMarshalText(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) {
- rv := reflect.ValueOf(v)
- if (code.Flags & AddrForMarshalerFlags) != 0 {
- if rv.CanAddr() {
- rv = rv.Addr()
- } else {
- newV := reflect.New(rv.Type())
- newV.Elem().Set(rv)
- rv = newV
- }
- }
- v = rv.Interface()
- marshaler, ok := v.(encoding.TextMarshaler)
- if !ok {
- return AppendNull(ctx, b), nil
- }
- bytes, err := marshaler.MarshalText()
- if err != nil {
- return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
- }
- return AppendString(ctx, b, *(*string)(unsafe.Pointer(&bytes))), nil
- }
- func AppendMarshalTextIndent(ctx *RuntimeContext, code *Opcode, b []byte, v interface{}) ([]byte, error) {
- rv := reflect.ValueOf(v)
- if (code.Flags & AddrForMarshalerFlags) != 0 {
- if rv.CanAddr() {
- rv = rv.Addr()
- } else {
- newV := reflect.New(rv.Type())
- newV.Elem().Set(rv)
- rv = newV
- }
- }
- v = rv.Interface()
- marshaler, ok := v.(encoding.TextMarshaler)
- if !ok {
- return AppendNull(ctx, b), nil
- }
- bytes, err := marshaler.MarshalText()
- if err != nil {
- return nil, &errors.MarshalerError{Type: reflect.TypeOf(v), Err: err}
- }
- return AppendString(ctx, b, *(*string)(unsafe.Pointer(&bytes))), nil
- }
- func AppendNull(_ *RuntimeContext, b []byte) []byte {
- return append(b, "null"...)
- }
- func AppendComma(_ *RuntimeContext, b []byte) []byte {
- return append(b, ',')
- }
- func AppendCommaIndent(_ *RuntimeContext, b []byte) []byte {
- return append(b, ',', '\n')
- }
- func AppendStructEnd(_ *RuntimeContext, b []byte) []byte {
- return append(b, '}', ',')
- }
- func AppendStructEndIndent(ctx *RuntimeContext, code *Opcode, b []byte) []byte {
- b = append(b, '\n')
- b = append(b, ctx.Prefix...)
- indentNum := ctx.BaseIndent + code.Indent - 1
- for i := uint32(0); i < indentNum; i++ {
- b = append(b, ctx.IndentStr...)
- }
- return append(b, '}', ',', '\n')
- }
- func AppendIndent(ctx *RuntimeContext, b []byte, indent uint32) []byte {
- b = append(b, ctx.Prefix...)
- indentNum := ctx.BaseIndent + indent
- for i := uint32(0); i < indentNum; i++ {
- b = append(b, ctx.IndentStr...)
- }
- return b
- }
- func IsNilForMarshaler(v interface{}) bool {
- rv := reflect.ValueOf(v)
- switch rv.Kind() {
- case reflect.Bool:
- return !rv.Bool()
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return rv.Int() == 0
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return rv.Uint() == 0
- case reflect.Float32, reflect.Float64:
- return math.Float64bits(rv.Float()) == 0
- case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Func:
- return rv.IsNil()
- case reflect.Slice:
- return rv.IsNil() || rv.Len() == 0
- case reflect.String:
- return rv.Len() == 0
- }
- return false
- }
|