package avro

import (
	
	
	
	
	

	
)

func createDecoderOfFixed( *FixedSchema,  reflect2.Type) ValDecoder {
	switch .Kind() {
	case reflect.Array:
		 := .(reflect2.ArrayType)
		if .Elem().Kind() != reflect.Uint8 || .Len() != .Size() {
			break
		}
		return &fixedCodec{arrayType: .(*reflect2.UnsafeArrayType)}
	case reflect.Uint64:
		if .Size() != 8 {
			break
		}

		return &fixedUint64Codec{}
	case reflect.Ptr:
		 := .(*reflect2.UnsafePtrType)
		 := .Elem()

		 := .Logical()
		 := .Type1()
		if .Kind() != reflect.Struct || !.ConvertibleTo(ratType) ||  == nil ||
			.Type() != Decimal {
			break
		}
		 := .(*DecimalLogicalSchema)
		return &fixedDecimalCodec{prec: .Precision(), scale: .Scale(), size: .Size()}
	case reflect.Struct:
		 := .Logical()
		if  == nil {
			break
		}
		 := .Type1()
		if !.ConvertibleTo(durType) || .Type() != Duration {
			break
		}
		return &fixedDurationCodec{}
	}

	return &errorDecoder{
		err: fmt.Errorf("avro: %s is unsupported for Avro %s, size=%d", .String(), .Type(), .Size()),
	}
}

func createEncoderOfFixed( *FixedSchema,  reflect2.Type) ValEncoder {
	switch .Kind() {
	case reflect.Array:
		 := .(reflect2.ArrayType)
		if .Elem().Kind() != reflect.Uint8 || .Len() != .Size() {
			break
		}
		return &fixedCodec{arrayType: .(*reflect2.UnsafeArrayType)}
	case reflect.Uint64:
		if .Size() != 8 {
			break
		}

		return &fixedUint64Codec{}
	case reflect.Ptr:
		 := .(*reflect2.UnsafePtrType)
		 := .Elem()

		 := .Logical()
		 := .Type1()
		if .Kind() != reflect.Struct || !.ConvertibleTo(ratType) ||  == nil ||
			.Type() != Decimal {
			break
		}
		 := .(*DecimalLogicalSchema)
		return &fixedDecimalCodec{prec: .Precision(), scale: .Scale(), size: .Size()}

	case reflect.Struct:
		 := .Logical()
		if  == nil {
			break
		}
		 := .Type1()
		if .ConvertibleTo(durType) && .Type() == Duration {
			return &fixedDurationCodec{}
		}
	}

	return &errorEncoder{
		err: fmt.Errorf("avro: %s is unsupported for Avro %s, size=%d", .String(), .Type(), .Size()),
	}
}

type fixedUint64Codec [8]byte

func ( *fixedUint64Codec) ( unsafe.Pointer,  *Reader) {
	 := [:]
	.Read()
	*(*uint64)() = binary.BigEndian.Uint64()
}

func ( *fixedUint64Codec) ( unsafe.Pointer,  *Writer) {
	 := [:]
	binary.BigEndian.PutUint64(, *(*uint64)())
	_, _ = .Write()
}

type fixedCodec struct {
	arrayType *reflect2.UnsafeArrayType
}

func ( *fixedCodec) ( unsafe.Pointer,  *Reader) {
	for  := range .arrayType.Len() {
		.arrayType.UnsafeSetIndex(, , reflect2.PtrOf(.readByte()))
	}
}

func ( *fixedCodec) ( unsafe.Pointer,  *Writer) {
	for  := range .arrayType.Len() {
		 := .arrayType.UnsafeGetIndex(, )
		.writeByte(*((*byte)()))
	}
}

type fixedDecimalCodec struct {
	prec  int
	scale int
	size  int
}

func ( *fixedDecimalCodec) ( unsafe.Pointer,  *Reader) {
	 := make([]byte, .size)
	.Read()
	*((**big.Rat)()) = ratFromBytes(, .scale)
}

func ( *fixedDecimalCodec) ( unsafe.Pointer,  *Writer) {
	 := *((**big.Rat)())
	 := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(.scale)), nil)
	 := (&big.Int{}).Mul(.Num(), )
	 = .Div(, .Denom())

	var  []byte
	switch .Sign() {
	case 0:
		 = make([]byte, .size)

	case 1:
		 = .Bytes()
		if [0]&0x80 > 0 {
			 = append([]byte{0}, ...)
		}
		if len() < .size {
			 := make([]byte, .size)
			copy([.size-len():], )
			 = 
		}

	case -1:
		 = .Add(, (&big.Int{}).Lsh(one, uint(.size*8))).Bytes()
	}

	_, _ = .Write()
}

type fixedDurationCodec struct{}

func (*fixedDurationCodec) ( unsafe.Pointer,  *Reader) {
	 := make([]byte, 12)
	.Read()
	var  LogicalDuration
	.Months = binary.LittleEndian.Uint32([0:4])
	.Days = binary.LittleEndian.Uint32([4:8])
	.Milliseconds = binary.LittleEndian.Uint32([8:12])
	*((*LogicalDuration)()) = 
}

func (*fixedDurationCodec) ( unsafe.Pointer,  *Writer) {
	 := (*LogicalDuration)()
	 := make([]byte, 4)
	binary.LittleEndian.PutUint32(, .Months)
	_, _ = .Write()
	binary.LittleEndian.PutUint32(, .Days)
	_, _ = .Write()
	binary.LittleEndian.PutUint32(, .Milliseconds)
	_, _ = .Write()
}