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  }