package decoder

import (
	
	
	
	
	
	
	
	

	
)

var (
	jsonNumberType   = reflect.TypeOf(json.Number(""))
	typeAddr         *runtime.TypeAddr
	cachedDecoderMap unsafe.Pointer // map[uintptr]decoder
	cachedDecoder    []Decoder
	initOnce         sync.Once
)

func initDecoder() {
	initOnce.Do(func() {
		typeAddr = runtime.AnalyzeTypeAddr()
		if typeAddr == nil {
			typeAddr = &runtime.TypeAddr{}
		}
		cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift+1)
	})
}

func loadDecoderMap() map[uintptr]Decoder {
	initDecoder()
	 := atomic.LoadPointer(&cachedDecoderMap)
	return *(*map[uintptr]Decoder)(unsafe.Pointer(&))
}

func storeDecoder( uintptr,  Decoder,  map[uintptr]Decoder) {
	initDecoder()
	 := make(map[uintptr]Decoder, len()+1)
	[] = 

	for ,  := range  {
		[] = 
	}

	atomic.StorePointer(&cachedDecoderMap, *(*unsafe.Pointer)(unsafe.Pointer(&)))
}

func compileToGetDecoderSlowPath( uintptr,  *runtime.Type) (Decoder, error) {
	 := loadDecoderMap()
	if ,  := [];  {
		return , nil
	}

	,  := compileHead(, map[uintptr]Decoder{})
	if  != nil {
		return nil, 
	}
	storeDecoder(, , )
	return , nil
}

func compileHead( *runtime.Type,  map[uintptr]Decoder) (Decoder, error) {
	switch {
	case implementsUnmarshalJSONType(runtime.PtrTo()):
		return newUnmarshalJSONDecoder(runtime.PtrTo(), "", ""), nil
	case runtime.PtrTo().Implements(unmarshalTextType):
		return newUnmarshalTextDecoder(runtime.PtrTo(), "", ""), nil
	}
	return compile(.Elem(), "", "", )
}

func compile( *runtime.Type, ,  string,  map[uintptr]Decoder) (Decoder, error) {
	switch {
	case implementsUnmarshalJSONType(runtime.PtrTo()):
		return newUnmarshalJSONDecoder(runtime.PtrTo(), , ), nil
	case runtime.PtrTo().Implements(unmarshalTextType):
		return newUnmarshalTextDecoder(runtime.PtrTo(), , ), nil
	}

	switch .Kind() {
	case reflect.Ptr:
		return compilePtr(, , , )
	case reflect.Struct:
		return compileStruct(, , , )
	case reflect.Slice:
		 := .Elem()
		if .Kind() == reflect.Uint8 {
			return compileBytes(, , )
		}
		return compileSlice(, , , )
	case reflect.Array:
		return compileArray(, , , )
	case reflect.Map:
		return compileMap(, , , )
	case reflect.Interface:
		return compileInterface(, , )
	case reflect.Uintptr:
		return compileUint(, , )
	case reflect.Int:
		return compileInt(, , )
	case reflect.Int8:
		return compileInt8(, , )
	case reflect.Int16:
		return compileInt16(, , )
	case reflect.Int32:
		return compileInt32(, , )
	case reflect.Int64:
		return compileInt64(, , )
	case reflect.Uint:
		return compileUint(, , )
	case reflect.Uint8:
		return compileUint8(, , )
	case reflect.Uint16:
		return compileUint16(, , )
	case reflect.Uint32:
		return compileUint32(, , )
	case reflect.Uint64:
		return compileUint64(, , )
	case reflect.String:
		return compileString(, , )
	case reflect.Bool:
		return compileBool(, )
	case reflect.Float32:
		return compileFloat32(, )
	case reflect.Float64:
		return compileFloat64(, )
	case reflect.Func:
		return compileFunc(, , )
	}
	return newInvalidDecoder(, , ), nil
}

func isStringTagSupportedType( *runtime.Type) bool {
	switch {
	case implementsUnmarshalJSONType(runtime.PtrTo()):
		return false
	case runtime.PtrTo().Implements(unmarshalTextType):
		return false
	}
	switch .Kind() {
	case reflect.Map:
		return false
	case reflect.Slice:
		return false
	case reflect.Array:
		return false
	case reflect.Struct:
		return false
	case reflect.Interface:
		return false
	}
	return true
}

func compileMapKey( *runtime.Type, ,  string,  map[uintptr]Decoder) (Decoder, error) {
	if runtime.PtrTo().Implements(unmarshalTextType) {
		return newUnmarshalTextDecoder(runtime.PtrTo(), , ), nil
	}
	if .Kind() == reflect.String {
		return newStringDecoder(, ), nil
	}
	,  := compile(, , , )
	if  != nil {
		return nil, 
	}
	for {
		switch t := .(type) {
		case *stringDecoder, *interfaceDecoder:
			return , nil
		case *boolDecoder, *intDecoder, *uintDecoder, *numberDecoder:
			return newWrappedStringDecoder(, , , ), nil
		case *ptrDecoder:
			 = .dec
		default:
			return newInvalidDecoder(, , ), nil
		}
	}
}

func compilePtr( *runtime.Type, ,  string,  map[uintptr]Decoder) (Decoder, error) {
	,  := compile(.Elem(), , , )
	if  != nil {
		return nil, 
	}
	return newPtrDecoder(, .Elem(), , ), nil
}

func compileInt( *runtime.Type, ,  string) (Decoder, error) {
	return newIntDecoder(, , , func( unsafe.Pointer,  int64) {
		*(*int)() = int()
	}), nil
}

func compileInt8( *runtime.Type, ,  string) (Decoder, error) {
	return newIntDecoder(, , , func( unsafe.Pointer,  int64) {
		*(*int8)() = int8()
	}), nil
}

func compileInt16( *runtime.Type, ,  string) (Decoder, error) {
	return newIntDecoder(, , , func( unsafe.Pointer,  int64) {
		*(*int16)() = int16()
	}), nil
}

func compileInt32( *runtime.Type, ,  string) (Decoder, error) {
	return newIntDecoder(, , , func( unsafe.Pointer,  int64) {
		*(*int32)() = int32()
	}), nil
}

func compileInt64( *runtime.Type, ,  string) (Decoder, error) {
	return newIntDecoder(, , , func( unsafe.Pointer,  int64) {
		*(*int64)() = 
	}), nil
}

func compileUint( *runtime.Type, ,  string) (Decoder, error) {
	return newUintDecoder(, , , func( unsafe.Pointer,  uint64) {
		*(*uint)() = uint()
	}), nil
}

func compileUint8( *runtime.Type, ,  string) (Decoder, error) {
	return newUintDecoder(, , , func( unsafe.Pointer,  uint64) {
		*(*uint8)() = uint8()
	}), nil
}

func compileUint16( *runtime.Type, ,  string) (Decoder, error) {
	return newUintDecoder(, , , func( unsafe.Pointer,  uint64) {
		*(*uint16)() = uint16()
	}), nil
}

func compileUint32( *runtime.Type, ,  string) (Decoder, error) {
	return newUintDecoder(, , , func( unsafe.Pointer,  uint64) {
		*(*uint32)() = uint32()
	}), nil
}

func compileUint64( *runtime.Type, ,  string) (Decoder, error) {
	return newUintDecoder(, , , func( unsafe.Pointer,  uint64) {
		*(*uint64)() = 
	}), nil
}

func compileFloat32(,  string) (Decoder, error) {
	return newFloatDecoder(, , func( unsafe.Pointer,  float64) {
		*(*float32)() = float32()
	}), nil
}

func compileFloat64(,  string) (Decoder, error) {
	return newFloatDecoder(, , func( unsafe.Pointer,  float64) {
		*(*float64)() = 
	}), nil
}

func compileString( *runtime.Type, ,  string) (Decoder, error) {
	if  == runtime.Type2RType(jsonNumberType) {
		return newNumberDecoder(, , func( unsafe.Pointer,  json.Number) {
			*(*json.Number)() = 
		}), nil
	}
	return newStringDecoder(, ), nil
}

func compileBool(,  string) (Decoder, error) {
	return newBoolDecoder(, ), nil
}

func compileBytes( *runtime.Type, ,  string) (Decoder, error) {
	return newBytesDecoder(, , ), nil
}

func compileSlice( *runtime.Type, ,  string,  map[uintptr]Decoder) (Decoder, error) {
	 := .Elem()
	,  := compile(, , , )
	if  != nil {
		return nil, 
	}
	return newSliceDecoder(, , .Size(), , ), nil
}

func compileArray( *runtime.Type, ,  string,  map[uintptr]Decoder) (Decoder, error) {
	 := .Elem()
	,  := compile(, , , )
	if  != nil {
		return nil, 
	}
	return newArrayDecoder(, , .Len(), , ), nil
}

func compileMap( *runtime.Type, ,  string,  map[uintptr]Decoder) (Decoder, error) {
	,  := compileMapKey(.Key(), , , )
	if  != nil {
		return nil, 
	}
	,  := compile(.Elem(), , , )
	if  != nil {
		return nil, 
	}
	return newMapDecoder(, .Key(), , .Elem(), , , ), nil
}

func compileInterface( *runtime.Type, ,  string) (Decoder, error) {
	return newInterfaceDecoder(, , ), nil
}

func compileFunc( *runtime.Type, ,  string) (Decoder, error) {
	return newFuncDecoder(, , ), nil
}

func typeToStructTags( *runtime.Type) runtime.StructTags {
	 := runtime.StructTags{}
	 := .NumField()
	for  := 0;  < ; ++ {
		 := .Field()
		if runtime.IsIgnoredStructField() {
			continue
		}
		 = append(, runtime.StructTagFromField())
	}
	return 
}

func compileStruct( *runtime.Type, ,  string,  map[uintptr]Decoder) (Decoder, error) {
	 := .NumField()
	 := map[string]*structFieldSet{}
	 := uintptr(unsafe.Pointer())
	if ,  := [];  {
		return , nil
	}
	 := newStructDecoder(, , )
	[] = 
	 = .Name()
	 := typeToStructTags()
	 := []*structFieldSet{}
	for  := 0;  < ; ++ {
		 := .Field()
		if runtime.IsIgnoredStructField() {
			continue
		}
		 := unicode.IsLower([]rune(.Name)[0])
		 := runtime.StructTagFromField()
		,  := compile(runtime.Type2RType(.Type), , .Name, )
		if  != nil {
			return nil, 
		}
		if .Anonymous && !.IsTaggedKey {
			if ,  := .(*structDecoder);  {
				if runtime.Type2RType(.Type) ==  {
					// recursive definition
					continue
				}
				for ,  := range .fieldMap {
					if .ExistsKey() {
						continue
					}
					 := &structFieldSet{
						dec:         .dec,
						offset:      .Offset + .offset,
						isTaggedKey: .isTaggedKey,
						key:         ,
						keyLen:      int64(len()),
					}
					 = append(, )
				}
			} else if ,  := .(*ptrDecoder);  {
				 := .contentDecoder()
				if .typ ==  {
					// recursive definition
					continue
				}
				var  error
				if  {
					 = fmt.Errorf(
						"json: cannot set embedded pointer to unexported struct: %v",
						.Type.Elem(),
					)
				}
				if ,  := .(*structDecoder);  {
					for ,  := range .fieldMap {
						if .ExistsKey() {
							continue
						}
						 := &structFieldSet{
							dec:         newAnonymousFieldDecoder(.typ, .offset, .dec),
							offset:      .Offset,
							isTaggedKey: .isTaggedKey,
							key:         ,
							keyLen:      int64(len()),
							err:         ,
						}
						 = append(, )
					}
				} else {
					 := &structFieldSet{
						dec:         ,
						offset:      .Offset,
						isTaggedKey: .IsTaggedKey,
						key:         .Name,
						keyLen:      int64(len(.Name)),
					}
					 = append(, )
				}
			} else {
				 := &structFieldSet{
					dec:         ,
					offset:      .Offset,
					isTaggedKey: .IsTaggedKey,
					key:         .Name,
					keyLen:      int64(len(.Name)),
				}
				 = append(, )
			}
		} else {
			if .IsString && isStringTagSupportedType(runtime.Type2RType(.Type)) {
				 = newWrappedStringDecoder(runtime.Type2RType(.Type), , , .Name)
			}
			var  string
			if .Key != "" {
				 = .Key
			} else {
				 = .Name
			}
			 := &structFieldSet{
				dec:         ,
				offset:      .Offset,
				isTaggedKey: .IsTaggedKey,
				key:         ,
				keyLen:      int64(len()),
			}
			 = append(, )
		}
	}
	for ,  := range filterDuplicatedFields() {
		[.key] = 
		 := strings.ToLower(.key)
		if ,  := []; ! {
			// first win
			[] = 
		}
	}
	delete(, )
	.tryOptimize()
	return , nil
}

func filterDuplicatedFields( []*structFieldSet) []*structFieldSet {
	 := map[string][]*structFieldSet{}
	for ,  := range  {
		[.key] = append([.key], )
	}
	 := map[string]struct{}{}
	for ,  := range  {
		 = filterFieldSets()
		if len() != 1 {
			[] = struct{}{}
		}
	}

	 := make([]*structFieldSet, 0, len())
	for ,  := range  {
		if ,  := [.key];  {
			continue
		}
		 = append(, )
	}
	return 
}

func filterFieldSets( []*structFieldSet) []*structFieldSet {
	if len() == 1 {
		return 
	}
	 := make([]*structFieldSet, 0, len())
	for ,  := range  {
		if .isTaggedKey {
			 = append(, )
		}
	}
	return 
}

func implementsUnmarshalJSONType( *runtime.Type) bool {
	return .Implements(unmarshalJSONType) || .Implements(unmarshalJSONContextType)
}