github.com/hamba/avro@v1.8.0/codec_fixed.go (about) 1 package avro 2 3 import ( 4 "fmt" 5 "math/big" 6 "reflect" 7 "unsafe" 8 9 "github.com/modern-go/reflect2" 10 ) 11 12 func createDecoderOfFixed(schema Schema, typ reflect2.Type) ValDecoder { 13 fixed := schema.(*FixedSchema) 14 switch typ.Kind() { 15 case reflect.Array: 16 arrayType := typ.(reflect2.ArrayType) 17 if arrayType.Elem().Kind() != reflect.Uint8 || arrayType.Len() != fixed.Size() { 18 break 19 } 20 return &fixedCodec{arrayType: typ.(*reflect2.UnsafeArrayType)} 21 22 case reflect.Struct: 23 ls := fixed.Logical() 24 if typ.RType() != ratRType || ls == nil || ls.Type() != Decimal { 25 break 26 } 27 dec := ls.(*DecimalLogicalSchema) 28 return &fixedDecimalCodec{prec: dec.Precision(), scale: dec.Scale(), size: fixed.Size()} 29 } 30 31 return &errorDecoder{err: fmt.Errorf("avro: %s is unsupported for Avro %s", typ.String(), schema.Type())} 32 } 33 34 func createEncoderOfFixed(schema Schema, typ reflect2.Type) ValEncoder { 35 fixed := schema.(*FixedSchema) 36 switch typ.Kind() { 37 case reflect.Array: 38 arrayType := typ.(reflect2.ArrayType) 39 fixed := schema.(*FixedSchema) 40 if arrayType.Elem().Kind() != reflect.Uint8 || arrayType.Len() != fixed.Size() { 41 break 42 } 43 return &fixedCodec{arrayType: typ.(*reflect2.UnsafeArrayType)} 44 45 case reflect.Ptr: 46 ptrType := typ.(*reflect2.UnsafePtrType) 47 elemType := ptrType.Elem() 48 49 ls := fixed.Logical() 50 if elemType.Kind() != reflect.Struct || elemType.RType() != ratRType || ls == nil || ls.Type() != Decimal { 51 break 52 } 53 dec := ls.(*DecimalLogicalSchema) 54 return &fixedDecimalCodec{prec: dec.Precision(), scale: dec.Scale(), size: fixed.Size()} 55 } 56 57 return &errorEncoder{err: fmt.Errorf("avro: %s is unsupported for Avro %s", typ.String(), schema.Type())} 58 } 59 60 type fixedCodec struct { 61 arrayType *reflect2.UnsafeArrayType 62 } 63 64 func (c *fixedCodec) Decode(ptr unsafe.Pointer, r *Reader) { 65 for i := 0; i < c.arrayType.Len(); i++ { 66 c.arrayType.UnsafeSetIndex(ptr, i, reflect2.PtrOf(r.readByte())) 67 } 68 } 69 70 func (c *fixedCodec) Encode(ptr unsafe.Pointer, w *Writer) { 71 for i := 0; i < c.arrayType.Len(); i++ { 72 bytePtr := c.arrayType.UnsafeGetIndex(ptr, i) 73 w.writeByte(*((*byte)(bytePtr))) 74 } 75 } 76 77 type fixedDecimalCodec struct { 78 prec int 79 scale int 80 size int 81 } 82 83 func (c *fixedDecimalCodec) Decode(ptr unsafe.Pointer, r *Reader) { 84 b := make([]byte, c.size) 85 r.Read(b) 86 *((*big.Rat)(ptr)) = *ratFromBytes(b, c.scale) 87 } 88 89 func (c *fixedDecimalCodec) Encode(ptr unsafe.Pointer, w *Writer) { 90 r := *((**big.Rat)(ptr)) 91 scale := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(c.scale)), nil) 92 i := (&big.Int{}).Mul(r.Num(), scale) 93 i = i.Div(i, r.Denom()) 94 95 var b []byte 96 switch i.Sign() { 97 case 0: 98 b = make([]byte, c.size) 99 100 case 1: 101 b = i.Bytes() 102 if b[0]&0x80 > 0 { 103 b = append([]byte{0}, b...) 104 } 105 if len(b) < c.size { 106 padded := make([]byte, c.size) 107 copy(padded[c.size-len(b):], b) 108 b = padded 109 } 110 111 case -1: 112 b = i.Add(i, (&big.Int{}).Lsh(one, uint(c.size*8))).Bytes() 113 } 114 115 w.Write(b) 116 }