mirror of
https://codeberg.org/superseriousbusiness/gotosocial.git
synced 2025-05-04 11:22:50 +03:00
[chore] update dependencies, bump to Go 1.19.1 (#826)
* 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>
This commit is contained in:
parent
00d38855d4
commit
a156188b3e
1135 changed files with 258905 additions and 137146 deletions
vendor/github.com/goccy/go-json/internal/encoder
930
vendor/github.com/goccy/go-json/internal/encoder/compiler.go
generated
vendored
Normal file
930
vendor/github.com/goccy/go-json/internal/encoder/compiler.go
generated
vendored
Normal file
|
@ -0,0 +1,930 @@
|
|||
package encoder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goccy/go-json/internal/errors"
|
||||
"github.com/goccy/go-json/internal/runtime"
|
||||
)
|
||||
|
||||
type marshalerContext interface {
|
||||
MarshalJSON(context.Context) ([]byte, error)
|
||||
}
|
||||
|
||||
var (
|
||||
marshalJSONType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
|
||||
marshalJSONContextType = reflect.TypeOf((*marshalerContext)(nil)).Elem()
|
||||
marshalTextType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
|
||||
jsonNumberType = reflect.TypeOf(json.Number(""))
|
||||
cachedOpcodeSets []*OpcodeSet
|
||||
cachedOpcodeMap unsafe.Pointer // map[uintptr]*OpcodeSet
|
||||
typeAddr *runtime.TypeAddr
|
||||
)
|
||||
|
||||
func init() {
|
||||
typeAddr = runtime.AnalyzeTypeAddr()
|
||||
if typeAddr == nil {
|
||||
typeAddr = &runtime.TypeAddr{}
|
||||
}
|
||||
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift+1)
|
||||
}
|
||||
|
||||
func loadOpcodeMap() map[uintptr]*OpcodeSet {
|
||||
p := atomic.LoadPointer(&cachedOpcodeMap)
|
||||
return *(*map[uintptr]*OpcodeSet)(unsafe.Pointer(&p))
|
||||
}
|
||||
|
||||
func storeOpcodeSet(typ uintptr, set *OpcodeSet, m map[uintptr]*OpcodeSet) {
|
||||
newOpcodeMap := make(map[uintptr]*OpcodeSet, len(m)+1)
|
||||
newOpcodeMap[typ] = set
|
||||
|
||||
for k, v := range m {
|
||||
newOpcodeMap[k] = v
|
||||
}
|
||||
|
||||
atomic.StorePointer(&cachedOpcodeMap, *(*unsafe.Pointer)(unsafe.Pointer(&newOpcodeMap)))
|
||||
}
|
||||
|
||||
func compileToGetCodeSetSlowPath(typeptr uintptr) (*OpcodeSet, error) {
|
||||
opcodeMap := loadOpcodeMap()
|
||||
if codeSet, exists := opcodeMap[typeptr]; exists {
|
||||
return codeSet, nil
|
||||
}
|
||||
codeSet, err := newCompiler().compile(typeptr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
storeOpcodeSet(typeptr, codeSet, opcodeMap)
|
||||
return codeSet, nil
|
||||
}
|
||||
|
||||
func getFilteredCodeSetIfNeeded(ctx *RuntimeContext, codeSet *OpcodeSet) (*OpcodeSet, error) {
|
||||
if (ctx.Option.Flag & ContextOption) == 0 {
|
||||
return codeSet, nil
|
||||
}
|
||||
query := FieldQueryFromContext(ctx.Option.Context)
|
||||
if query == nil {
|
||||
return codeSet, nil
|
||||
}
|
||||
ctx.Option.Flag |= FieldQueryOption
|
||||
cacheCodeSet := codeSet.getQueryCache(query.Hash())
|
||||
if cacheCodeSet != nil {
|
||||
return cacheCodeSet, nil
|
||||
}
|
||||
queryCodeSet, err := newCompiler().codeToOpcodeSet(codeSet.Type, codeSet.Code.Filter(query))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
codeSet.setQueryCache(query.Hash(), queryCodeSet)
|
||||
return queryCodeSet, nil
|
||||
}
|
||||
|
||||
type Compiler struct {
|
||||
structTypeToCode map[uintptr]*StructCode
|
||||
}
|
||||
|
||||
func newCompiler() *Compiler {
|
||||
return &Compiler{
|
||||
structTypeToCode: map[uintptr]*StructCode{},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Compiler) compile(typeptr uintptr) (*OpcodeSet, error) {
|
||||
// noescape trick for header.typ ( reflect.*rtype )
|
||||
typ := *(**runtime.Type)(unsafe.Pointer(&typeptr))
|
||||
code, err := c.typeToCode(typ)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.codeToOpcodeSet(typ, code)
|
||||
}
|
||||
|
||||
func (c *Compiler) codeToOpcodeSet(typ *runtime.Type, code Code) (*OpcodeSet, error) {
|
||||
noescapeKeyCode := c.codeToOpcode(&compileContext{
|
||||
structTypeToCodes: map[uintptr]Opcodes{},
|
||||
recursiveCodes: &Opcodes{},
|
||||
}, typ, code)
|
||||
if err := noescapeKeyCode.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
escapeKeyCode := c.codeToOpcode(&compileContext{
|
||||
structTypeToCodes: map[uintptr]Opcodes{},
|
||||
recursiveCodes: &Opcodes{},
|
||||
escapeKey: true,
|
||||
}, typ, code)
|
||||
noescapeKeyCode = copyOpcode(noescapeKeyCode)
|
||||
escapeKeyCode = copyOpcode(escapeKeyCode)
|
||||
setTotalLengthToInterfaceOp(noescapeKeyCode)
|
||||
setTotalLengthToInterfaceOp(escapeKeyCode)
|
||||
interfaceNoescapeKeyCode := copyToInterfaceOpcode(noescapeKeyCode)
|
||||
interfaceEscapeKeyCode := copyToInterfaceOpcode(escapeKeyCode)
|
||||
codeLength := noescapeKeyCode.TotalLength()
|
||||
return &OpcodeSet{
|
||||
Type: typ,
|
||||
NoescapeKeyCode: noescapeKeyCode,
|
||||
EscapeKeyCode: escapeKeyCode,
|
||||
InterfaceNoescapeKeyCode: interfaceNoescapeKeyCode,
|
||||
InterfaceEscapeKeyCode: interfaceEscapeKeyCode,
|
||||
CodeLength: codeLength,
|
||||
EndCode: ToEndCode(interfaceNoescapeKeyCode),
|
||||
Code: code,
|
||||
QueryCache: map[string]*OpcodeSet{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Compiler) typeToCode(typ *runtime.Type) (Code, error) {
|
||||
switch {
|
||||
case c.implementsMarshalJSON(typ):
|
||||
return c.marshalJSONCode(typ)
|
||||
case c.implementsMarshalText(typ):
|
||||
return c.marshalTextCode(typ)
|
||||
}
|
||||
|
||||
isPtr := false
|
||||
orgType := typ
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
typ = typ.Elem()
|
||||
isPtr = true
|
||||
}
|
||||
switch {
|
||||
case c.implementsMarshalJSON(typ):
|
||||
return c.marshalJSONCode(orgType)
|
||||
case c.implementsMarshalText(typ):
|
||||
return c.marshalTextCode(orgType)
|
||||
}
|
||||
switch typ.Kind() {
|
||||
case reflect.Slice:
|
||||
elem := typ.Elem()
|
||||
if elem.Kind() == reflect.Uint8 {
|
||||
p := runtime.PtrTo(elem)
|
||||
if !c.implementsMarshalJSONType(p) && !p.Implements(marshalTextType) {
|
||||
return c.bytesCode(typ, isPtr)
|
||||
}
|
||||
}
|
||||
return c.sliceCode(typ)
|
||||
case reflect.Map:
|
||||
if isPtr {
|
||||
return c.ptrCode(runtime.PtrTo(typ))
|
||||
}
|
||||
return c.mapCode(typ)
|
||||
case reflect.Struct:
|
||||
return c.structCode(typ, isPtr)
|
||||
case reflect.Int:
|
||||
return c.intCode(typ, isPtr)
|
||||
case reflect.Int8:
|
||||
return c.int8Code(typ, isPtr)
|
||||
case reflect.Int16:
|
||||
return c.int16Code(typ, isPtr)
|
||||
case reflect.Int32:
|
||||
return c.int32Code(typ, isPtr)
|
||||
case reflect.Int64:
|
||||
return c.int64Code(typ, isPtr)
|
||||
case reflect.Uint, reflect.Uintptr:
|
||||
return c.uintCode(typ, isPtr)
|
||||
case reflect.Uint8:
|
||||
return c.uint8Code(typ, isPtr)
|
||||
case reflect.Uint16:
|
||||
return c.uint16Code(typ, isPtr)
|
||||
case reflect.Uint32:
|
||||
return c.uint32Code(typ, isPtr)
|
||||
case reflect.Uint64:
|
||||
return c.uint64Code(typ, isPtr)
|
||||
case reflect.Float32:
|
||||
return c.float32Code(typ, isPtr)
|
||||
case reflect.Float64:
|
||||
return c.float64Code(typ, isPtr)
|
||||
case reflect.String:
|
||||
return c.stringCode(typ, isPtr)
|
||||
case reflect.Bool:
|
||||
return c.boolCode(typ, isPtr)
|
||||
case reflect.Interface:
|
||||
return c.interfaceCode(typ, isPtr)
|
||||
default:
|
||||
if isPtr && typ.Implements(marshalTextType) {
|
||||
typ = orgType
|
||||
}
|
||||
return c.typeToCodeWithPtr(typ, isPtr)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Compiler) typeToCodeWithPtr(typ *runtime.Type, isPtr bool) (Code, error) {
|
||||
switch {
|
||||
case c.implementsMarshalJSON(typ):
|
||||
return c.marshalJSONCode(typ)
|
||||
case c.implementsMarshalText(typ):
|
||||
return c.marshalTextCode(typ)
|
||||
}
|
||||
switch typ.Kind() {
|
||||
case reflect.Ptr:
|
||||
return c.ptrCode(typ)
|
||||
case reflect.Slice:
|
||||
elem := typ.Elem()
|
||||
if elem.Kind() == reflect.Uint8 {
|
||||
p := runtime.PtrTo(elem)
|
||||
if !c.implementsMarshalJSONType(p) && !p.Implements(marshalTextType) {
|
||||
return c.bytesCode(typ, false)
|
||||
}
|
||||
}
|
||||
return c.sliceCode(typ)
|
||||
case reflect.Array:
|
||||
return c.arrayCode(typ)
|
||||
case reflect.Map:
|
||||
return c.mapCode(typ)
|
||||
case reflect.Struct:
|
||||
return c.structCode(typ, isPtr)
|
||||
case reflect.Interface:
|
||||
return c.interfaceCode(typ, false)
|
||||
case reflect.Int:
|
||||
return c.intCode(typ, false)
|
||||
case reflect.Int8:
|
||||
return c.int8Code(typ, false)
|
||||
case reflect.Int16:
|
||||
return c.int16Code(typ, false)
|
||||
case reflect.Int32:
|
||||
return c.int32Code(typ, false)
|
||||
case reflect.Int64:
|
||||
return c.int64Code(typ, false)
|
||||
case reflect.Uint:
|
||||
return c.uintCode(typ, false)
|
||||
case reflect.Uint8:
|
||||
return c.uint8Code(typ, false)
|
||||
case reflect.Uint16:
|
||||
return c.uint16Code(typ, false)
|
||||
case reflect.Uint32:
|
||||
return c.uint32Code(typ, false)
|
||||
case reflect.Uint64:
|
||||
return c.uint64Code(typ, false)
|
||||
case reflect.Uintptr:
|
||||
return c.uintCode(typ, false)
|
||||
case reflect.Float32:
|
||||
return c.float32Code(typ, false)
|
||||
case reflect.Float64:
|
||||
return c.float64Code(typ, false)
|
||||
case reflect.String:
|
||||
return c.stringCode(typ, false)
|
||||
case reflect.Bool:
|
||||
return c.boolCode(typ, false)
|
||||
}
|
||||
return nil, &errors.UnsupportedTypeError{Type: runtime.RType2Type(typ)}
|
||||
}
|
||||
|
||||
const intSize = 32 << (^uint(0) >> 63)
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) intCode(typ *runtime.Type, isPtr bool) (*IntCode, error) {
|
||||
return &IntCode{typ: typ, bitSize: intSize, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) int8Code(typ *runtime.Type, isPtr bool) (*IntCode, error) {
|
||||
return &IntCode{typ: typ, bitSize: 8, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) int16Code(typ *runtime.Type, isPtr bool) (*IntCode, error) {
|
||||
return &IntCode{typ: typ, bitSize: 16, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) int32Code(typ *runtime.Type, isPtr bool) (*IntCode, error) {
|
||||
return &IntCode{typ: typ, bitSize: 32, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) int64Code(typ *runtime.Type, isPtr bool) (*IntCode, error) {
|
||||
return &IntCode{typ: typ, bitSize: 64, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) uintCode(typ *runtime.Type, isPtr bool) (*UintCode, error) {
|
||||
return &UintCode{typ: typ, bitSize: intSize, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) uint8Code(typ *runtime.Type, isPtr bool) (*UintCode, error) {
|
||||
return &UintCode{typ: typ, bitSize: 8, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) uint16Code(typ *runtime.Type, isPtr bool) (*UintCode, error) {
|
||||
return &UintCode{typ: typ, bitSize: 16, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) uint32Code(typ *runtime.Type, isPtr bool) (*UintCode, error) {
|
||||
return &UintCode{typ: typ, bitSize: 32, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) uint64Code(typ *runtime.Type, isPtr bool) (*UintCode, error) {
|
||||
return &UintCode{typ: typ, bitSize: 64, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) float32Code(typ *runtime.Type, isPtr bool) (*FloatCode, error) {
|
||||
return &FloatCode{typ: typ, bitSize: 32, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) float64Code(typ *runtime.Type, isPtr bool) (*FloatCode, error) {
|
||||
return &FloatCode{typ: typ, bitSize: 64, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) stringCode(typ *runtime.Type, isPtr bool) (*StringCode, error) {
|
||||
return &StringCode{typ: typ, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) boolCode(typ *runtime.Type, isPtr bool) (*BoolCode, error) {
|
||||
return &BoolCode{typ: typ, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) intStringCode(typ *runtime.Type) (*IntCode, error) {
|
||||
return &IntCode{typ: typ, bitSize: intSize, isString: true}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) int8StringCode(typ *runtime.Type) (*IntCode, error) {
|
||||
return &IntCode{typ: typ, bitSize: 8, isString: true}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) int16StringCode(typ *runtime.Type) (*IntCode, error) {
|
||||
return &IntCode{typ: typ, bitSize: 16, isString: true}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) int32StringCode(typ *runtime.Type) (*IntCode, error) {
|
||||
return &IntCode{typ: typ, bitSize: 32, isString: true}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) int64StringCode(typ *runtime.Type) (*IntCode, error) {
|
||||
return &IntCode{typ: typ, bitSize: 64, isString: true}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) uintStringCode(typ *runtime.Type) (*UintCode, error) {
|
||||
return &UintCode{typ: typ, bitSize: intSize, isString: true}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) uint8StringCode(typ *runtime.Type) (*UintCode, error) {
|
||||
return &UintCode{typ: typ, bitSize: 8, isString: true}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) uint16StringCode(typ *runtime.Type) (*UintCode, error) {
|
||||
return &UintCode{typ: typ, bitSize: 16, isString: true}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) uint32StringCode(typ *runtime.Type) (*UintCode, error) {
|
||||
return &UintCode{typ: typ, bitSize: 32, isString: true}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) uint64StringCode(typ *runtime.Type) (*UintCode, error) {
|
||||
return &UintCode{typ: typ, bitSize: 64, isString: true}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) bytesCode(typ *runtime.Type, isPtr bool) (*BytesCode, error) {
|
||||
return &BytesCode{typ: typ, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) interfaceCode(typ *runtime.Type, isPtr bool) (*InterfaceCode, error) {
|
||||
return &InterfaceCode{typ: typ, isPtr: isPtr}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) marshalJSONCode(typ *runtime.Type) (*MarshalJSONCode, error) {
|
||||
return &MarshalJSONCode{
|
||||
typ: typ,
|
||||
isAddrForMarshaler: c.isPtrMarshalJSONType(typ),
|
||||
isNilableType: c.isNilableType(typ),
|
||||
isMarshalerContext: typ.Implements(marshalJSONContextType) || runtime.PtrTo(typ).Implements(marshalJSONContextType),
|
||||
}, nil
|
||||
}
|
||||
|
||||
//nolint:unparam
|
||||
func (c *Compiler) marshalTextCode(typ *runtime.Type) (*MarshalTextCode, error) {
|
||||
return &MarshalTextCode{
|
||||
typ: typ,
|
||||
isAddrForMarshaler: c.isPtrMarshalTextType(typ),
|
||||
isNilableType: c.isNilableType(typ),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Compiler) ptrCode(typ *runtime.Type) (*PtrCode, error) {
|
||||
code, err := c.typeToCodeWithPtr(typ.Elem(), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, ok := code.(*PtrCode)
|
||||
if ok {
|
||||
return &PtrCode{typ: typ, value: ptr.value, ptrNum: ptr.ptrNum + 1}, nil
|
||||
}
|
||||
return &PtrCode{typ: typ, value: code, ptrNum: 1}, nil
|
||||
}
|
||||
|
||||
func (c *Compiler) sliceCode(typ *runtime.Type) (*SliceCode, error) {
|
||||
elem := typ.Elem()
|
||||
code, err := c.listElemCode(elem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if code.Kind() == CodeKindStruct {
|
||||
structCode := code.(*StructCode)
|
||||
structCode.enableIndirect()
|
||||
}
|
||||
return &SliceCode{typ: typ, value: code}, nil
|
||||
}
|
||||
|
||||
func (c *Compiler) arrayCode(typ *runtime.Type) (*ArrayCode, error) {
|
||||
elem := typ.Elem()
|
||||
code, err := c.listElemCode(elem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if code.Kind() == CodeKindStruct {
|
||||
structCode := code.(*StructCode)
|
||||
structCode.enableIndirect()
|
||||
}
|
||||
return &ArrayCode{typ: typ, value: code}, nil
|
||||
}
|
||||
|
||||
func (c *Compiler) mapCode(typ *runtime.Type) (*MapCode, error) {
|
||||
keyCode, err := c.mapKeyCode(typ.Key())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
valueCode, err := c.mapValueCode(typ.Elem())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if valueCode.Kind() == CodeKindStruct {
|
||||
structCode := valueCode.(*StructCode)
|
||||
structCode.enableIndirect()
|
||||
}
|
||||
return &MapCode{typ: typ, key: keyCode, value: valueCode}, nil
|
||||
}
|
||||
|
||||
func (c *Compiler) listElemCode(typ *runtime.Type) (Code, error) {
|
||||
switch {
|
||||
case c.isPtrMarshalJSONType(typ):
|
||||
return c.marshalJSONCode(typ)
|
||||
case !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType):
|
||||
return c.marshalTextCode(typ)
|
||||
case typ.Kind() == reflect.Map:
|
||||
return c.ptrCode(runtime.PtrTo(typ))
|
||||
default:
|
||||
// isPtr was originally used to indicate whether the type of top level is pointer.
|
||||
// However, since the slice/array element is a specification that can get the pointer address, explicitly set isPtr to true.
|
||||
// See here for related issues: https://github.com/goccy/go-json/issues/370
|
||||
code, err := c.typeToCodeWithPtr(typ, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, ok := code.(*PtrCode)
|
||||
if ok {
|
||||
if ptr.value.Kind() == CodeKindMap {
|
||||
ptr.ptrNum++
|
||||
}
|
||||
}
|
||||
return code, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Compiler) mapKeyCode(typ *runtime.Type) (Code, error) {
|
||||
switch {
|
||||
case c.implementsMarshalJSON(typ):
|
||||
return c.marshalJSONCode(typ)
|
||||
case c.implementsMarshalText(typ):
|
||||
return c.marshalTextCode(typ)
|
||||
}
|
||||
switch typ.Kind() {
|
||||
case reflect.Ptr:
|
||||
return c.ptrCode(typ)
|
||||
case reflect.String:
|
||||
return c.stringCode(typ, false)
|
||||
case reflect.Int:
|
||||
return c.intStringCode(typ)
|
||||
case reflect.Int8:
|
||||
return c.int8StringCode(typ)
|
||||
case reflect.Int16:
|
||||
return c.int16StringCode(typ)
|
||||
case reflect.Int32:
|
||||
return c.int32StringCode(typ)
|
||||
case reflect.Int64:
|
||||
return c.int64StringCode(typ)
|
||||
case reflect.Uint:
|
||||
return c.uintStringCode(typ)
|
||||
case reflect.Uint8:
|
||||
return c.uint8StringCode(typ)
|
||||
case reflect.Uint16:
|
||||
return c.uint16StringCode(typ)
|
||||
case reflect.Uint32:
|
||||
return c.uint32StringCode(typ)
|
||||
case reflect.Uint64:
|
||||
return c.uint64StringCode(typ)
|
||||
case reflect.Uintptr:
|
||||
return c.uintStringCode(typ)
|
||||
}
|
||||
return nil, &errors.UnsupportedTypeError{Type: runtime.RType2Type(typ)}
|
||||
}
|
||||
|
||||
func (c *Compiler) mapValueCode(typ *runtime.Type) (Code, error) {
|
||||
switch typ.Kind() {
|
||||
case reflect.Map:
|
||||
return c.ptrCode(runtime.PtrTo(typ))
|
||||
default:
|
||||
code, err := c.typeToCodeWithPtr(typ, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ptr, ok := code.(*PtrCode)
|
||||
if ok {
|
||||
if ptr.value.Kind() == CodeKindMap {
|
||||
ptr.ptrNum++
|
||||
}
|
||||
}
|
||||
return code, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Compiler) structCode(typ *runtime.Type, isPtr bool) (*StructCode, error) {
|
||||
typeptr := uintptr(unsafe.Pointer(typ))
|
||||
if code, exists := c.structTypeToCode[typeptr]; exists {
|
||||
derefCode := *code
|
||||
derefCode.isRecursive = true
|
||||
return &derefCode, nil
|
||||
}
|
||||
indirect := runtime.IfaceIndir(typ)
|
||||
code := &StructCode{typ: typ, isPtr: isPtr, isIndirect: indirect}
|
||||
c.structTypeToCode[typeptr] = code
|
||||
|
||||
fieldNum := typ.NumField()
|
||||
tags := c.typeToStructTags(typ)
|
||||
fields := []*StructFieldCode{}
|
||||
for i, tag := range tags {
|
||||
isOnlyOneFirstField := i == 0 && fieldNum == 1
|
||||
field, err := c.structFieldCode(code, tag, isPtr, isOnlyOneFirstField)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if field.isAnonymous {
|
||||
structCode := field.getAnonymousStruct()
|
||||
if structCode != nil {
|
||||
structCode.removeFieldsByTags(tags)
|
||||
if c.isAssignableIndirect(field, isPtr) {
|
||||
if indirect {
|
||||
structCode.isIndirect = true
|
||||
} else {
|
||||
structCode.isIndirect = false
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
structCode := field.getStruct()
|
||||
if structCode != nil {
|
||||
if indirect {
|
||||
// if parent is indirect type, set child indirect property to true
|
||||
structCode.isIndirect = true
|
||||
} else {
|
||||
// if parent is not indirect type, set child indirect property to false.
|
||||
// but if parent's indirect is false and isPtr is true, then indirect must be true.
|
||||
// Do this only if indirectConversion is enabled at the end of compileStruct.
|
||||
structCode.isIndirect = false
|
||||
}
|
||||
}
|
||||
}
|
||||
fields = append(fields, field)
|
||||
}
|
||||
fieldMap := c.getFieldMap(fields)
|
||||
duplicatedFieldMap := c.getDuplicatedFieldMap(fieldMap)
|
||||
code.fields = c.filteredDuplicatedFields(fields, duplicatedFieldMap)
|
||||
if !code.disableIndirectConversion && !indirect && isPtr {
|
||||
code.enableIndirect()
|
||||
}
|
||||
delete(c.structTypeToCode, typeptr)
|
||||
return code, nil
|
||||
}
|
||||
|
||||
func (c *Compiler) structFieldCode(structCode *StructCode, tag *runtime.StructTag, isPtr, isOnlyOneFirstField bool) (*StructFieldCode, error) {
|
||||
field := tag.Field
|
||||
fieldType := runtime.Type2RType(field.Type)
|
||||
isIndirectSpecialCase := isPtr && isOnlyOneFirstField
|
||||
fieldCode := &StructFieldCode{
|
||||
typ: fieldType,
|
||||
key: tag.Key,
|
||||
tag: tag,
|
||||
offset: field.Offset,
|
||||
isAnonymous: field.Anonymous && !tag.IsTaggedKey,
|
||||
isTaggedKey: tag.IsTaggedKey,
|
||||
isNilableType: c.isNilableType(fieldType),
|
||||
isNilCheck: true,
|
||||
}
|
||||
switch {
|
||||
case c.isMovePointerPositionFromHeadToFirstMarshalJSONFieldCase(fieldType, isIndirectSpecialCase):
|
||||
code, err := c.marshalJSONCode(fieldType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldCode.value = code
|
||||
fieldCode.isAddrForMarshaler = true
|
||||
fieldCode.isNilCheck = false
|
||||
structCode.isIndirect = false
|
||||
structCode.disableIndirectConversion = true
|
||||
case c.isMovePointerPositionFromHeadToFirstMarshalTextFieldCase(fieldType, isIndirectSpecialCase):
|
||||
code, err := c.marshalTextCode(fieldType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldCode.value = code
|
||||
fieldCode.isAddrForMarshaler = true
|
||||
fieldCode.isNilCheck = false
|
||||
structCode.isIndirect = false
|
||||
structCode.disableIndirectConversion = true
|
||||
case isPtr && c.isPtrMarshalJSONType(fieldType):
|
||||
// *struct{ field T }
|
||||
// func (*T) MarshalJSON() ([]byte, error)
|
||||
code, err := c.marshalJSONCode(fieldType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldCode.value = code
|
||||
fieldCode.isAddrForMarshaler = true
|
||||
fieldCode.isNilCheck = false
|
||||
case isPtr && c.isPtrMarshalTextType(fieldType):
|
||||
// *struct{ field T }
|
||||
// func (*T) MarshalText() ([]byte, error)
|
||||
code, err := c.marshalTextCode(fieldType)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
fieldCode.value = code
|
||||
fieldCode.isAddrForMarshaler = true
|
||||
fieldCode.isNilCheck = false
|
||||
default:
|
||||
code, err := c.typeToCodeWithPtr(fieldType, isPtr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch code.Kind() {
|
||||
case CodeKindPtr, CodeKindInterface:
|
||||
fieldCode.isNextOpPtrType = true
|
||||
}
|
||||
fieldCode.value = code
|
||||
}
|
||||
return fieldCode, nil
|
||||
}
|
||||
|
||||
func (c *Compiler) isAssignableIndirect(fieldCode *StructFieldCode, isPtr bool) bool {
|
||||
if isPtr {
|
||||
return false
|
||||
}
|
||||
codeType := fieldCode.value.Kind()
|
||||
if codeType == CodeKindMarshalJSON {
|
||||
return false
|
||||
}
|
||||
if codeType == CodeKindMarshalText {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Compiler) getFieldMap(fields []*StructFieldCode) map[string][]*StructFieldCode {
|
||||
fieldMap := map[string][]*StructFieldCode{}
|
||||
for _, field := range fields {
|
||||
if field.isAnonymous {
|
||||
for k, v := range c.getAnonymousFieldMap(field) {
|
||||
fieldMap[k] = append(fieldMap[k], v...)
|
||||
}
|
||||
continue
|
||||
}
|
||||
fieldMap[field.key] = append(fieldMap[field.key], field)
|
||||
}
|
||||
return fieldMap
|
||||
}
|
||||
|
||||
func (c *Compiler) getAnonymousFieldMap(field *StructFieldCode) map[string][]*StructFieldCode {
|
||||
fieldMap := map[string][]*StructFieldCode{}
|
||||
structCode := field.getAnonymousStruct()
|
||||
if structCode == nil || structCode.isRecursive {
|
||||
fieldMap[field.key] = append(fieldMap[field.key], field)
|
||||
return fieldMap
|
||||
}
|
||||
for k, v := range c.getFieldMapFromAnonymousParent(structCode.fields) {
|
||||
fieldMap[k] = append(fieldMap[k], v...)
|
||||
}
|
||||
return fieldMap
|
||||
}
|
||||
|
||||
func (c *Compiler) getFieldMapFromAnonymousParent(fields []*StructFieldCode) map[string][]*StructFieldCode {
|
||||
fieldMap := map[string][]*StructFieldCode{}
|
||||
for _, field := range fields {
|
||||
if field.isAnonymous {
|
||||
for k, v := range c.getAnonymousFieldMap(field) {
|
||||
// Do not handle tagged key when embedding more than once
|
||||
for _, vv := range v {
|
||||
vv.isTaggedKey = false
|
||||
}
|
||||
fieldMap[k] = append(fieldMap[k], v...)
|
||||
}
|
||||
continue
|
||||
}
|
||||
fieldMap[field.key] = append(fieldMap[field.key], field)
|
||||
}
|
||||
return fieldMap
|
||||
}
|
||||
|
||||
func (c *Compiler) getDuplicatedFieldMap(fieldMap map[string][]*StructFieldCode) map[*StructFieldCode]struct{} {
|
||||
duplicatedFieldMap := map[*StructFieldCode]struct{}{}
|
||||
for _, fields := range fieldMap {
|
||||
if len(fields) == 1 {
|
||||
continue
|
||||
}
|
||||
if c.isTaggedKeyOnly(fields) {
|
||||
for _, field := range fields {
|
||||
if field.isTaggedKey {
|
||||
continue
|
||||
}
|
||||
duplicatedFieldMap[field] = struct{}{}
|
||||
}
|
||||
} else {
|
||||
for _, field := range fields {
|
||||
duplicatedFieldMap[field] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
return duplicatedFieldMap
|
||||
}
|
||||
|
||||
func (c *Compiler) filteredDuplicatedFields(fields []*StructFieldCode, duplicatedFieldMap map[*StructFieldCode]struct{}) []*StructFieldCode {
|
||||
filteredFields := make([]*StructFieldCode, 0, len(fields))
|
||||
for _, field := range fields {
|
||||
if field.isAnonymous {
|
||||
structCode := field.getAnonymousStruct()
|
||||
if structCode != nil && !structCode.isRecursive {
|
||||
structCode.fields = c.filteredDuplicatedFields(structCode.fields, duplicatedFieldMap)
|
||||
if len(structCode.fields) > 0 {
|
||||
filteredFields = append(filteredFields, field)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
if _, exists := duplicatedFieldMap[field]; exists {
|
||||
continue
|
||||
}
|
||||
filteredFields = append(filteredFields, field)
|
||||
}
|
||||
return filteredFields
|
||||
}
|
||||
|
||||
func (c *Compiler) isTaggedKeyOnly(fields []*StructFieldCode) bool {
|
||||
var taggedKeyFieldCount int
|
||||
for _, field := range fields {
|
||||
if field.isTaggedKey {
|
||||
taggedKeyFieldCount++
|
||||
}
|
||||
}
|
||||
return taggedKeyFieldCount == 1
|
||||
}
|
||||
|
||||
func (c *Compiler) typeToStructTags(typ *runtime.Type) runtime.StructTags {
|
||||
tags := runtime.StructTags{}
|
||||
fieldNum := typ.NumField()
|
||||
for i := 0; i < fieldNum; i++ {
|
||||
field := typ.Field(i)
|
||||
if runtime.IsIgnoredStructField(field) {
|
||||
continue
|
||||
}
|
||||
tags = append(tags, runtime.StructTagFromField(field))
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
// *struct{ field T } => struct { field *T }
|
||||
// func (*T) MarshalJSON() ([]byte, error)
|
||||
func (c *Compiler) isMovePointerPositionFromHeadToFirstMarshalJSONFieldCase(typ *runtime.Type, isIndirectSpecialCase bool) bool {
|
||||
return isIndirectSpecialCase && !c.isNilableType(typ) && c.isPtrMarshalJSONType(typ)
|
||||
}
|
||||
|
||||
// *struct{ field T } => struct { field *T }
|
||||
// func (*T) MarshalText() ([]byte, error)
|
||||
func (c *Compiler) isMovePointerPositionFromHeadToFirstMarshalTextFieldCase(typ *runtime.Type, isIndirectSpecialCase bool) bool {
|
||||
return isIndirectSpecialCase && !c.isNilableType(typ) && c.isPtrMarshalTextType(typ)
|
||||
}
|
||||
|
||||
func (c *Compiler) implementsMarshalJSON(typ *runtime.Type) bool {
|
||||
if !c.implementsMarshalJSONType(typ) {
|
||||
return false
|
||||
}
|
||||
if typ.Kind() != reflect.Ptr {
|
||||
return true
|
||||
}
|
||||
// type kind is reflect.Ptr
|
||||
if !c.implementsMarshalJSONType(typ.Elem()) {
|
||||
return true
|
||||
}
|
||||
// needs to dereference
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Compiler) implementsMarshalText(typ *runtime.Type) bool {
|
||||
if !typ.Implements(marshalTextType) {
|
||||
return false
|
||||
}
|
||||
if typ.Kind() != reflect.Ptr {
|
||||
return true
|
||||
}
|
||||
// type kind is reflect.Ptr
|
||||
if !typ.Elem().Implements(marshalTextType) {
|
||||
return true
|
||||
}
|
||||
// needs to dereference
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Compiler) isNilableType(typ *runtime.Type) bool {
|
||||
if !runtime.IfaceIndir(typ) {
|
||||
return true
|
||||
}
|
||||
switch typ.Kind() {
|
||||
case reflect.Ptr:
|
||||
return true
|
||||
case reflect.Map:
|
||||
return true
|
||||
case reflect.Func:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Compiler) implementsMarshalJSONType(typ *runtime.Type) bool {
|
||||
return typ.Implements(marshalJSONType) || typ.Implements(marshalJSONContextType)
|
||||
}
|
||||
|
||||
func (c *Compiler) isPtrMarshalJSONType(typ *runtime.Type) bool {
|
||||
return !c.implementsMarshalJSONType(typ) && c.implementsMarshalJSONType(runtime.PtrTo(typ))
|
||||
}
|
||||
|
||||
func (c *Compiler) isPtrMarshalTextType(typ *runtime.Type) bool {
|
||||
return !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType)
|
||||
}
|
||||
|
||||
func (c *Compiler) codeToOpcode(ctx *compileContext, typ *runtime.Type, code Code) *Opcode {
|
||||
codes := code.ToOpcode(ctx)
|
||||
codes.Last().Next = newEndOp(ctx, typ)
|
||||
c.linkRecursiveCode(ctx)
|
||||
return codes.First()
|
||||
}
|
||||
|
||||
func (c *Compiler) linkRecursiveCode(ctx *compileContext) {
|
||||
recursiveCodes := map[uintptr]*CompiledCode{}
|
||||
for _, recursive := range *ctx.recursiveCodes {
|
||||
typeptr := uintptr(unsafe.Pointer(recursive.Type))
|
||||
codes := ctx.structTypeToCodes[typeptr]
|
||||
if recursiveCode, ok := recursiveCodes[typeptr]; ok {
|
||||
*recursive.Jmp = *recursiveCode
|
||||
continue
|
||||
}
|
||||
|
||||
code := copyOpcode(codes.First())
|
||||
code.Op = code.Op.PtrHeadToHead()
|
||||
lastCode := newEndOp(&compileContext{}, recursive.Type)
|
||||
lastCode.Op = OpRecursiveEnd
|
||||
|
||||
// OpRecursiveEnd must set before call TotalLength
|
||||
code.End.Next = lastCode
|
||||
|
||||
totalLength := code.TotalLength()
|
||||
|
||||
// Idx, ElemIdx, Length must set after call TotalLength
|
||||
lastCode.Idx = uint32((totalLength + 1) * uintptrSize)
|
||||
lastCode.ElemIdx = lastCode.Idx + uintptrSize
|
||||
lastCode.Length = lastCode.Idx + 2*uintptrSize
|
||||
|
||||
// extend length to alloc slot for elemIdx + length
|
||||
curTotalLength := uintptr(recursive.TotalLength()) + 3
|
||||
nextTotalLength := uintptr(totalLength) + 3
|
||||
|
||||
compiled := recursive.Jmp
|
||||
compiled.Code = code
|
||||
compiled.CurLen = curTotalLength
|
||||
compiled.NextLen = nextTotalLength
|
||||
compiled.Linked = true
|
||||
|
||||
recursiveCodes[typeptr] = compiled
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue