github.com/hamba/avro@v1.8.0/codec_array.go (about) 1 package avro 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 "reflect" 8 "unsafe" 9 10 "github.com/modern-go/reflect2" 11 ) 12 13 func createDecoderOfArray(cfg *frozenConfig, schema Schema, typ reflect2.Type) ValDecoder { 14 if typ.Kind() == reflect.Slice { 15 return decoderOfArray(cfg, schema, typ) 16 } 17 18 return &errorDecoder{err: fmt.Errorf("avro: %s is unsupported for Avro %s", typ.String(), schema.Type())} 19 } 20 21 func createEncoderOfArray(cfg *frozenConfig, schema Schema, typ reflect2.Type) ValEncoder { 22 if typ.Kind() == reflect.Slice { 23 return encoderOfArray(cfg, schema, typ) 24 } 25 26 return &errorEncoder{err: fmt.Errorf("avro: %s is unsupported for Avro %s", typ.String(), schema.Type())} 27 } 28 29 func decoderOfArray(cfg *frozenConfig, schema Schema, typ reflect2.Type) ValDecoder { 30 arr := schema.(*ArraySchema) 31 sliceType := typ.(*reflect2.UnsafeSliceType) 32 decoder := decoderOfType(cfg, arr.Items(), sliceType.Elem()) 33 34 return &arrayDecoder{typ: sliceType, decoder: decoder} 35 } 36 37 type arrayDecoder struct { 38 typ *reflect2.UnsafeSliceType 39 decoder ValDecoder 40 } 41 42 func (d *arrayDecoder) Decode(ptr unsafe.Pointer, r *Reader) { 43 var size int 44 sliceType := d.typ 45 46 for { 47 l, _ := r.ReadBlockHeader() 48 if l == 0 { 49 break 50 } 51 52 start := size 53 size += int(l) 54 sliceType.UnsafeGrow(ptr, size) 55 56 for i := start; i < size; i++ { 57 elemPtr := sliceType.UnsafeGetIndex(ptr, i) 58 d.decoder.Decode(elemPtr, r) 59 } 60 } 61 62 if r.Error != nil && !errors.Is(r.Error, io.EOF) { 63 r.Error = fmt.Errorf("%v: %w", d.typ, r.Error) 64 } 65 } 66 67 func encoderOfArray(cfg *frozenConfig, schema Schema, typ reflect2.Type) ValEncoder { 68 arr := schema.(*ArraySchema) 69 sliceType := typ.(*reflect2.UnsafeSliceType) 70 encoder := encoderOfType(cfg, arr.Items(), sliceType.Elem()) 71 72 return &arrayEncoder{ 73 blockLength: cfg.getBlockLength(), 74 typ: sliceType, 75 encoder: encoder, 76 } 77 } 78 79 type arrayEncoder struct { 80 blockLength int 81 typ *reflect2.UnsafeSliceType 82 encoder ValEncoder 83 } 84 85 func (e *arrayEncoder) Encode(ptr unsafe.Pointer, w *Writer) { 86 blockLength := e.blockLength 87 length := e.typ.UnsafeLengthOf(ptr) 88 89 for i := 0; i < length; i += blockLength { 90 w.WriteBlockCB(func(w *Writer) int64 { 91 count := int64(0) 92 for j := i; j < i+blockLength && j < length; j++ { 93 elemPtr := e.typ.UnsafeGetIndex(ptr, j) 94 e.encoder.Encode(elemPtr, w) 95 count++ 96 } 97 98 return count 99 }) 100 } 101 102 w.WriteBlockHeader(0, 0) 103 104 if w.Error != nil && !errors.Is(w.Error, io.EOF) { 105 w.Error = fmt.Errorf("%v: %w", e.typ, w.Error) 106 } 107 }