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  }