github.com/aacfactory/avro@v1.2.12/internal/base/codec_array.go (about) 1 package base 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 if r.Error != nil && !errors.Is(r.Error, io.EOF) { 60 r.Error = fmt.Errorf("%s: %w", d.typ.String(), r.Error) 61 return 62 } 63 } 64 } 65 66 if r.Error != nil && !errors.Is(r.Error, io.EOF) { 67 r.Error = fmt.Errorf("%v: %w", d.typ, r.Error) 68 } 69 } 70 71 func encoderOfArray(cfg *frozenConfig, schema Schema, typ reflect2.Type) ValEncoder { 72 arr := schema.(*ArraySchema) 73 sliceType := typ.(*reflect2.UnsafeSliceType) 74 encoder := encoderOfType(cfg, arr.Items(), sliceType.Elem()) 75 76 return &arrayEncoder{ 77 blockLength: cfg.getBlockLength(), 78 typ: sliceType, 79 encoder: encoder, 80 } 81 } 82 83 type arrayEncoder struct { 84 blockLength int 85 typ *reflect2.UnsafeSliceType 86 encoder ValEncoder 87 } 88 89 func (e *arrayEncoder) Encode(ptr unsafe.Pointer, w *Writer) { 90 blockLength := e.blockLength 91 length := e.typ.UnsafeLengthOf(ptr) 92 93 for i := 0; i < length; i += blockLength { 94 w.WriteBlockCB(func(w *Writer) int64 { 95 count := int64(0) 96 for j := i; j < i+blockLength && j < length; j++ { 97 elemPtr := e.typ.UnsafeGetIndex(ptr, j) 98 e.encoder.Encode(elemPtr, w) 99 if w.Error != nil && !errors.Is(w.Error, io.EOF) { 100 w.Error = fmt.Errorf("%s: %w", e.typ.String(), w.Error) 101 return count 102 } 103 count++ 104 } 105 106 return count 107 }) 108 } 109 110 w.WriteBlockHeader(0, 0) 111 112 if w.Error != nil && !errors.Is(w.Error, io.EOF) { 113 w.Error = fmt.Errorf("%v: %w", e.typ, w.Error) 114 } 115 }