github.com/aacfactory/avro@v1.2.12/internal/base/codec_fixed.go (about) 1 package base 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "math/big" 7 "reflect" 8 "unsafe" 9 10 "github.com/modern-go/reflect2" 11 ) 12 13 func createDecoderOfFixed(schema Schema, typ reflect2.Type) ValDecoder { 14 fixed := schema.(*FixedSchema) 15 switch typ.Kind() { 16 case reflect.Array: 17 arrayType := typ.(reflect2.ArrayType) 18 if arrayType.Elem().Kind() != reflect.Uint8 || arrayType.Len() != fixed.Size() { 19 break 20 } 21 return &fixedCodec{arrayType: typ.(*reflect2.UnsafeArrayType)} 22 23 case reflect.Uint64: 24 fixed := schema.(*FixedSchema) 25 if fixed.Size() != 8 { 26 break 27 } 28 29 return &fixedUint64Codec{} 30 31 case reflect.Struct: 32 ls := fixed.Logical() 33 if ls == nil { 34 break 35 } 36 typ1 := typ.Type1() 37 switch { 38 case typ1.ConvertibleTo(durType) && ls.Type() == Duration: 39 return &fixedDurationCodec{} 40 case typ1.ConvertibleTo(ratType) && ls.Type() == Decimal: 41 dec := ls.(*DecimalLogicalSchema) 42 return &fixedDecimalCodec{prec: dec.Precision(), scale: dec.Scale(), size: fixed.Size()} 43 } 44 default: 45 break 46 } 47 48 return &errorDecoder{ 49 err: fmt.Errorf("avro: %s is unsupported for Avro %s, size=%d", typ.String(), schema.Type(), fixed.Size()), 50 } 51 } 52 53 func createEncoderOfFixed(schema Schema, typ reflect2.Type) ValEncoder { 54 fixed := schema.(*FixedSchema) 55 switch typ.Kind() { 56 case reflect.Array: 57 arrayType := typ.(reflect2.ArrayType) 58 fixed := schema.(*FixedSchema) 59 if arrayType.Elem().Kind() != reflect.Uint8 || arrayType.Len() != fixed.Size() { 60 break 61 } 62 return &fixedCodec{arrayType: typ.(*reflect2.UnsafeArrayType)} 63 64 case reflect.Uint64: 65 fixed := schema.(*FixedSchema) 66 if fixed.Size() != 8 { 67 break 68 } 69 70 return &fixedUint64Codec{} 71 72 case reflect.Ptr: 73 ptrType := typ.(*reflect2.UnsafePtrType) 74 elemType := ptrType.Elem() 75 76 ls := fixed.Logical() 77 tpy1 := elemType.Type1() 78 if elemType.Kind() != reflect.Struct || !tpy1.ConvertibleTo(ratType) || ls == nil || 79 ls.Type() != Decimal { 80 break 81 } 82 dec := ls.(*DecimalLogicalSchema) 83 return &fixedDecimalCodec{prec: dec.Precision(), scale: dec.Scale(), size: fixed.Size()} 84 85 case reflect.Struct: 86 ls := fixed.Logical() 87 if ls == nil { 88 break 89 } 90 typ1 := typ.Type1() 91 if typ1.ConvertibleTo(durType) && ls.Type() == Duration { 92 return &fixedDurationCodec{} 93 } 94 default: 95 break 96 } 97 98 return &errorEncoder{ 99 err: fmt.Errorf("avro: %s is unsupported for Avro %s, size=%d", typ.String(), schema.Type(), fixed.Size()), 100 } 101 } 102 103 type fixedUint64Codec [8]byte 104 105 func (c *fixedUint64Codec) Decode(ptr unsafe.Pointer, r *Reader) { 106 buffer := c[:] 107 r.Read(buffer) 108 *(*uint64)(ptr) = binary.BigEndian.Uint64(buffer) 109 } 110 111 func (c *fixedUint64Codec) Encode(ptr unsafe.Pointer, w *Writer) { 112 buffer := c[:] 113 binary.BigEndian.PutUint64(buffer, *(*uint64)(ptr)) 114 _, _ = w.Write(buffer) 115 } 116 117 type fixedCodec struct { 118 arrayType *reflect2.UnsafeArrayType 119 } 120 121 func (c *fixedCodec) Decode(ptr unsafe.Pointer, r *Reader) { 122 for i := 0; i < c.arrayType.Len(); i++ { 123 c.arrayType.UnsafeSetIndex(ptr, i, reflect2.PtrOf(r.readByte())) 124 } 125 } 126 127 func (c *fixedCodec) Encode(ptr unsafe.Pointer, w *Writer) { 128 for i := 0; i < c.arrayType.Len(); i++ { 129 bytePtr := c.arrayType.UnsafeGetIndex(ptr, i) 130 w.writeByte(*((*byte)(bytePtr))) 131 } 132 } 133 134 type fixedDecimalCodec struct { 135 prec int 136 scale int 137 size int 138 } 139 140 func (c *fixedDecimalCodec) Decode(ptr unsafe.Pointer, r *Reader) { 141 b := make([]byte, c.size) 142 r.Read(b) 143 *((*big.Rat)(ptr)) = *ratFromBytes(b, c.scale) 144 } 145 146 func (c *fixedDecimalCodec) Encode(ptr unsafe.Pointer, w *Writer) { 147 r := *((**big.Rat)(ptr)) 148 scale := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(c.scale)), nil) 149 i := (&big.Int{}).Mul(r.Num(), scale) 150 i = i.Div(i, r.Denom()) 151 152 var b []byte 153 switch i.Sign() { 154 case 0: 155 b = make([]byte, c.size) 156 157 case 1: 158 b = i.Bytes() 159 if b[0]&0x80 > 0 { 160 b = append([]byte{0}, b...) 161 } 162 if len(b) < c.size { 163 padded := make([]byte, c.size) 164 copy(padded[c.size-len(b):], b) 165 b = padded 166 } 167 168 case -1: 169 b = i.Add(i, (&big.Int{}).Lsh(one, uint(c.size*8))).Bytes() 170 } 171 172 _, _ = w.Write(b) 173 } 174 175 type fixedDurationCodec struct{} 176 177 func (*fixedDurationCodec) Decode(ptr unsafe.Pointer, r *Reader) { 178 b := make([]byte, 12) 179 r.Read(b) 180 var duration LogicalDuration 181 duration.Months = binary.LittleEndian.Uint32(b[0:4]) 182 duration.Days = binary.LittleEndian.Uint32(b[4:8]) 183 duration.Milliseconds = binary.LittleEndian.Uint32(b[8:12]) 184 *((*LogicalDuration)(ptr)) = duration 185 } 186 187 func (*fixedDurationCodec) Encode(ptr unsafe.Pointer, w *Writer) { 188 duration := (*LogicalDuration)(ptr) 189 b := make([]byte, 4) 190 binary.LittleEndian.PutUint32(b, duration.Months) 191 _, _ = w.Write(b) 192 binary.LittleEndian.PutUint32(b, duration.Days) 193 _, _ = w.Write(b) 194 binary.LittleEndian.PutUint32(b, duration.Milliseconds) 195 _, _ = w.Write(b) 196 }