github.com/hamba/avro@v1.8.0/codec_map.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 createDecoderOfMap(cfg *frozenConfig, schema Schema, typ reflect2.Type) ValDecoder {
    14  	if typ.Kind() == reflect.Map && typ.(reflect2.MapType).Key().Kind() == reflect.String {
    15  		return decoderOfMap(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 createEncoderOfMap(cfg *frozenConfig, schema Schema, typ reflect2.Type) ValEncoder {
    22  	if typ.Kind() == reflect.Map && typ.(reflect2.MapType).Key().Kind() == reflect.String {
    23  		return encoderOfMap(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 decoderOfMap(cfg *frozenConfig, schema Schema, typ reflect2.Type) ValDecoder {
    30  	m := schema.(*MapSchema)
    31  	mapType := typ.(*reflect2.UnsafeMapType)
    32  	decoder := decoderOfType(cfg, m.Values(), mapType.Elem())
    33  
    34  	return &mapDecoder{
    35  		mapType:  mapType,
    36  		elemType: mapType.Elem(),
    37  		decoder:  decoder,
    38  	}
    39  }
    40  
    41  type mapDecoder struct {
    42  	mapType  *reflect2.UnsafeMapType
    43  	elemType reflect2.Type
    44  	decoder  ValDecoder
    45  }
    46  
    47  func (d *mapDecoder) Decode(ptr unsafe.Pointer, r *Reader) {
    48  	if d.mapType.UnsafeIsNil(ptr) {
    49  		d.mapType.UnsafeSet(ptr, d.mapType.UnsafeMakeMap(0))
    50  	}
    51  
    52  	for {
    53  		l, _ := r.ReadBlockHeader()
    54  		if l == 0 {
    55  			break
    56  		}
    57  
    58  		for i := int64(0); i < l; i++ {
    59  			keyPtr := reflect2.PtrOf(r.ReadString())
    60  			elemPtr := d.elemType.UnsafeNew()
    61  			d.decoder.Decode(elemPtr, r)
    62  
    63  			d.mapType.UnsafeSetIndex(ptr, keyPtr, elemPtr)
    64  		}
    65  	}
    66  
    67  	if r.Error != nil && !errors.Is(r.Error, io.EOF) {
    68  		r.Error = fmt.Errorf("%v: %w", d.mapType, r.Error)
    69  	}
    70  }
    71  
    72  func encoderOfMap(cfg *frozenConfig, schema Schema, typ reflect2.Type) ValEncoder {
    73  	m := schema.(*MapSchema)
    74  	mapType := typ.(*reflect2.UnsafeMapType)
    75  	encoder := encoderOfType(cfg, m.Values(), mapType.Elem())
    76  
    77  	return &mapEncoder{
    78  		blockLength: cfg.getBlockLength(),
    79  		mapType:     mapType,
    80  		encoder:     encoder,
    81  	}
    82  }
    83  
    84  type mapEncoder struct {
    85  	blockLength int
    86  	mapType     *reflect2.UnsafeMapType
    87  	encoder     ValEncoder
    88  }
    89  
    90  func (e *mapEncoder) Encode(ptr unsafe.Pointer, w *Writer) {
    91  	blockLength := e.blockLength
    92  
    93  	iter := e.mapType.UnsafeIterate(ptr)
    94  
    95  	for {
    96  		wrote := w.WriteBlockCB(func(w *Writer) int64 {
    97  			var i int
    98  			for i = 0; iter.HasNext() && i < blockLength; i++ {
    99  				keyPtr, elemPtr := iter.UnsafeNext()
   100  				w.WriteString(*((*string)(keyPtr)))
   101  				e.encoder.Encode(elemPtr, w)
   102  			}
   103  
   104  			return int64(i)
   105  		})
   106  
   107  		if wrote == 0 {
   108  			break
   109  		}
   110  	}
   111  
   112  	if w.Error != nil && !errors.Is(w.Error, io.EOF) {
   113  		w.Error = fmt.Errorf("%v: %w", e.mapType, w.Error)
   114  	}
   115  }