github.com/hamba/avro/v2@v2.22.1-0.20240518180522-aff3955acf7d/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 55 if size > r.cfg.getMaxSliceAllocSize() { 56 r.ReportError("decode array", "size is greater than `Config.MaxSliceAllocSize`") 57 return 58 } 59 60 sliceType.UnsafeGrow(ptr, size) 61 62 for i := start; i < size; i++ { 63 elemPtr := sliceType.UnsafeGetIndex(ptr, i) 64 d.decoder.Decode(elemPtr, r) 65 if r.Error != nil { 66 r.Error = fmt.Errorf("reading %s: %w", d.typ.String(), r.Error) 67 return 68 } 69 } 70 } 71 72 if r.Error != nil && !errors.Is(r.Error, io.EOF) { 73 r.Error = fmt.Errorf("%v: %w", d.typ, r.Error) 74 } 75 } 76 77 func encoderOfArray(cfg *frozenConfig, schema Schema, typ reflect2.Type) ValEncoder { 78 arr := schema.(*ArraySchema) 79 sliceType := typ.(*reflect2.UnsafeSliceType) 80 encoder := encoderOfType(cfg, arr.Items(), sliceType.Elem()) 81 82 return &arrayEncoder{ 83 blockLength: cfg.getBlockLength(), 84 typ: sliceType, 85 encoder: encoder, 86 } 87 } 88 89 type arrayEncoder struct { 90 blockLength int 91 typ *reflect2.UnsafeSliceType 92 encoder ValEncoder 93 } 94 95 func (e *arrayEncoder) Encode(ptr unsafe.Pointer, w *Writer) { 96 blockLength := e.blockLength 97 length := e.typ.UnsafeLengthOf(ptr) 98 99 for i := 0; i < length; i += blockLength { 100 w.WriteBlockCB(func(w *Writer) int64 { 101 count := int64(0) 102 for j := i; j < i+blockLength && j < length; j++ { 103 elemPtr := e.typ.UnsafeGetIndex(ptr, j) 104 e.encoder.Encode(elemPtr, w) 105 if w.Error != nil && !errors.Is(w.Error, io.EOF) { 106 w.Error = fmt.Errorf("%s: %w", e.typ.String(), w.Error) 107 return count 108 } 109 count++ 110 } 111 112 return count 113 }) 114 } 115 116 w.WriteBlockHeader(0, 0) 117 118 if w.Error != nil && !errors.Is(w.Error, io.EOF) { 119 w.Error = fmt.Errorf("%v: %w", e.typ, w.Error) 120 } 121 }