mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 23:12:26 -06:00 
			
		
		
		
	* update dependencies, bump Go version to 1.19 * bump test image Go version * update golangci-lint * update gotosocial-drone-build * sign * linting, go fmt * update swagger docs * update swagger docs * whitespace * update contributing.md * fuckin whoopsie doopsie * linterino, linteroni * fix followrequest test not starting processor * fix other api/client tests not starting processor * fix remaining tests where processor not started * bump go-runners version * don't check last-webfingered-at, processor may have updated this * update swagger command * update bun to latest version * fix embed to work the same as before with new bun Signed-off-by: kim <grufwub@gmail.com> Co-authored-by: tsmethurst <tobi.smethurst@protonmail.com>
		
			
				
	
	
		
			596 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			596 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
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 // whether recursive code already have linked
 | 
						|
	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)
 | 
						|
	/*
 | 
						|
		for i := 0; i < ptrNum; i++ {
 | 
						|
			if p == 0 {
 | 
						|
				return p
 | 
						|
			}
 | 
						|
			p = PtrToPtr(p)
 | 
						|
		}
 | 
						|
		return 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]
 | 
						|
}
 | 
						|
 | 
						|
//nolint:structcheck,unused
 | 
						|
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)
 | 
						|
}
 | 
						|
 | 
						|
//go:linkname MapIterInit runtime.mapiterinit
 | 
						|
//go:noescape
 | 
						|
func MapIterInit(mapType *runtime.Type, m unsafe.Pointer, it *mapIter)
 | 
						|
 | 
						|
//go:linkname MapIterKey reflect.mapiterkey
 | 
						|
//go:noescape
 | 
						|
func MapIterKey(it *mapIter) unsafe.Pointer
 | 
						|
 | 
						|
//go:linkname MapIterNext reflect.mapiternext
 | 
						|
//go:noescape
 | 
						|
func MapIterNext(it *mapIter)
 | 
						|
 | 
						|
//go:linkname MapLen reflect.maplen
 | 
						|
//go:noescape
 | 
						|
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')
 | 
						|
	// Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
 | 
						|
	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')
 | 
						|
	// Note: Must use float32 comparisons for underlying float32 value to get precise cutoffs right.
 | 
						|
	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) // convert by dynamic interface type
 | 
						|
	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) // convert by dynamic interface type
 | 
						|
	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) // convert by dynamic interface type
 | 
						|
	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) // convert by dynamic interface type
 | 
						|
	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
 | 
						|
}
 |