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 }