package avro

import (
	
	
	
	
	

	
)

var (
	timeType         = reflect.TypeOf(time.Time{})
	timeDurationType = reflect.TypeOf(time.Duration(0))
	ratType          = reflect.TypeOf(big.Rat{})
	durType          = reflect.TypeOf(LogicalDuration{})
)

type null struct{}

// ValDecoder represents an internal value decoder.
//
// You should never use ValDecoder directly.
type ValDecoder interface {
	Decode(ptr unsafe.Pointer, r *Reader)
}

// ValEncoder represents an internal value encoder.
//
// You should never use ValEncoder directly.
type ValEncoder interface {
	Encode(ptr unsafe.Pointer, w *Writer)
}

// ReadVal parses Avro value and stores the result in the value pointed to by obj.
func ( *Reader) ( Schema,  any) {
	 := .cfg.getDecoderFromCache(.CacheFingerprint(), reflect2.RTypeOf())
	if  == nil {
		 := reflect2.TypeOf()
		if .Kind() != reflect.Ptr {
			.ReportError("ReadVal", "can only unmarshal into pointer")
			return
		}
		 = .cfg.DecoderOf(, )
	}

	 := reflect2.PtrOf()
	if  == nil {
		.ReportError("ReadVal", "can not read into nil pointer")
		return
	}

	.Decode(, )
}

// WriteVal writes the Avro encoding of obj.
func ( *Writer) ( Schema,  any) {
	 := .cfg.getEncoderFromCache(.Fingerprint(), reflect2.RTypeOf())
	if  == nil {
		 := reflect2.TypeOf()
		 = .cfg.EncoderOf(, )
	}
	.Encode(reflect2.PtrOf(), )
}

func ( *frozenConfig) ( Schema,  reflect2.Type) ValDecoder {
	 := .RType()
	 := .getDecoderFromCache(.CacheFingerprint(), )
	if  != nil {
		return 
	}

	 := .(*reflect2.UnsafePtrType)
	 = decoderOfType(newDecoderContext(), , .Elem())
	.addDecoderToCache(.CacheFingerprint(), , )
	return 
}

type deferDecoder struct {
	decoder ValDecoder
}

func ( *deferDecoder) ( unsafe.Pointer,  *Reader) {
	.decoder.Decode(, )
}

type deferEncoder struct {
	encoder ValEncoder
}

func ( *deferEncoder) ( unsafe.Pointer,  *Writer) {
	.encoder.Encode(, )
}

type decoderContext struct {
	cfg      *frozenConfig
	decoders map[cacheKey]ValDecoder
}

func newDecoderContext( *frozenConfig) *decoderContext {
	return &decoderContext{
		cfg:      ,
		decoders: make(map[cacheKey]ValDecoder),
	}
}

type encoderContext struct {
	cfg      *frozenConfig
	encoders map[cacheKey]ValEncoder
}

func newEncoderContext( *frozenConfig) *encoderContext {
	return &encoderContext{
		cfg:      ,
		encoders: make(map[cacheKey]ValEncoder),
	}
}

//nolint:dupl
func decoderOfType( *decoderContext,  Schema,  reflect2.Type) ValDecoder {
	if  := createDecoderOfMarshaler(, );  != nil {
		return 
	}

	// Handle eface (empty interface) case when it isn't a union
	if .Kind() == reflect.Interface && .Type() != Union {
		if ,  := .(*reflect2.UnsafeIFaceType); ! {
			return newEfaceDecoder(, )
		}
	}

	switch .Type() {
	case Null:
		return &nullCodec{}
	case String, Bytes, Int, Long, Float, Double, Boolean:
		return createDecoderOfNative(.(*PrimitiveSchema), )
	case Record:
		 := cacheKey{fingerprint: .CacheFingerprint(), rtype: .RType()}
		 := &deferDecoder{}
		.decoders[] = 
		.decoder = createDecoderOfRecord(, .(*RecordSchema), )
		return .decoder
	case Ref:
		 := cacheKey{fingerprint: .(*RefSchema).Schema().CacheFingerprint(), rtype: .RType()}
		if ,  := .decoders[];  {
			return 
		}
		return (, .(*RefSchema).Schema(), )
	case Enum:
		return createDecoderOfEnum(.(*EnumSchema), )
	case Array:
		return createDecoderOfArray(, .(*ArraySchema), )
	case Map:
		return createDecoderOfMap(, .(*MapSchema), )
	case Union:
		return createDecoderOfUnion(, .(*UnionSchema), )
	case Fixed:
		return createDecoderOfFixed(.(*FixedSchema), )
	default:
		// It is impossible to get here with a valid schema
		return &errorDecoder{err: fmt.Errorf("avro: schema type %s is unsupported", .Type())}
	}
}

func ( *frozenConfig) ( Schema,  reflect2.Type) ValEncoder {
	if  == nil {
		 = reflect2.TypeOf((*null)(nil))
	}

	 := .RType()
	 := .getEncoderFromCache(.Fingerprint(), )
	if  != nil {
		return 
	}

	 = encoderOfType(newEncoderContext(), , )
	if .LikePtr() {
		 = &onePtrEncoder{}
	}
	.addEncoderToCache(.Fingerprint(), , )
	return 
}

type onePtrEncoder struct {
	enc ValEncoder
}

func ( *onePtrEncoder) ( unsafe.Pointer,  *Writer) {
	.enc.Encode(noescape(unsafe.Pointer(&)), )
}

//nolint:dupl
func encoderOfType( *encoderContext,  Schema,  reflect2.Type) ValEncoder {
	if  := createEncoderOfMarshaler(, );  != nil {
		return 
	}

	if .Kind() == reflect.Interface {
		return &interfaceEncoder{schema: , typ: }
	}

	switch .Type() {
	case Null:
		return &nullCodec{}
	case String, Bytes, Int, Long, Float, Double, Boolean:
		return createEncoderOfNative(.(*PrimitiveSchema), )
	case Record:
		 := cacheKey{fingerprint: .Fingerprint(), rtype: .RType()}
		 := &deferEncoder{}
		.encoders[] = 
		.encoder = createEncoderOfRecord(, .(*RecordSchema), )
		return .encoder
	case Ref:
		 := cacheKey{fingerprint: .(*RefSchema).Schema().Fingerprint(), rtype: .RType()}
		if ,  := .encoders[];  {
			return 
		}
		return (, .(*RefSchema).Schema(), )
	case Enum:
		return createEncoderOfEnum(.(*EnumSchema), )
	case Array:
		return createEncoderOfArray(, .(*ArraySchema), )
	case Map:
		return createEncoderOfMap(, .(*MapSchema), )
	case Union:
		return createEncoderOfUnion(, .(*UnionSchema), )
	case Fixed:
		return createEncoderOfFixed(.(*FixedSchema), )
	default:
		// It is impossible to get here with a valid schema
		return &errorEncoder{err: fmt.Errorf("avro: schema type %s is unsupported", .Type())}
	}
}

type errorDecoder struct {
	err error
}

func ( *errorDecoder) ( unsafe.Pointer,  *Reader) {
	if .Error == nil {
		.Error = .err
	}
}

type errorEncoder struct {
	err error
}

func ( *errorEncoder) ( unsafe.Pointer,  *Writer) {
	if .Error == nil {
		.Error = .err
	}
}