github.com/hamba/avro/v2@v2.22.1-0.20240518180522-aff3955acf7d/codec.go (about) 1 package avro 2 3 import ( 4 "fmt" 5 "math/big" 6 "reflect" 7 "time" 8 "unsafe" 9 10 "github.com/modern-go/reflect2" 11 ) 12 13 var ( 14 timeType = reflect.TypeOf(time.Time{}) 15 ratType = reflect.TypeOf(big.Rat{}) 16 durType = reflect.TypeOf(LogicalDuration{}) 17 ) 18 19 type null struct{} 20 21 // ValDecoder represents an internal value decoder. 22 // 23 // You should never use ValDecoder directly. 24 type ValDecoder interface { 25 Decode(ptr unsafe.Pointer, r *Reader) 26 } 27 28 // ValEncoder represents an internal value encoder. 29 // 30 // You should never use ValEncoder directly. 31 type ValEncoder interface { 32 Encode(ptr unsafe.Pointer, w *Writer) 33 } 34 35 // ReadVal parses Avro value and stores the result in the value pointed to by obj. 36 func (r *Reader) ReadVal(schema Schema, obj any) { 37 decoder := r.cfg.getDecoderFromCache(schema.CacheFingerprint(), reflect2.RTypeOf(obj)) 38 if decoder == nil { 39 typ := reflect2.TypeOf(obj) 40 if typ.Kind() != reflect.Ptr { 41 r.ReportError("ReadVal", "can only unmarshal into pointer") 42 return 43 } 44 decoder = r.cfg.DecoderOf(schema, typ) 45 } 46 47 ptr := reflect2.PtrOf(obj) 48 if ptr == nil { 49 r.ReportError("ReadVal", "can not read into nil pointer") 50 return 51 } 52 53 decoder.Decode(ptr, r) 54 } 55 56 // WriteVal writes the Avro encoding of obj. 57 func (w *Writer) WriteVal(schema Schema, val any) { 58 encoder := w.cfg.getEncoderFromCache(schema.Fingerprint(), reflect2.RTypeOf(val)) 59 if encoder == nil { 60 typ := reflect2.TypeOf(val) 61 encoder = w.cfg.EncoderOf(schema, typ) 62 } 63 encoder.Encode(reflect2.PtrOf(val), w) 64 } 65 66 func (c *frozenConfig) DecoderOf(schema Schema, typ reflect2.Type) ValDecoder { 67 rtype := typ.RType() 68 decoder := c.getDecoderFromCache(schema.CacheFingerprint(), rtype) 69 if decoder != nil { 70 return decoder 71 } 72 73 ptrType := typ.(*reflect2.UnsafePtrType) 74 decoder = decoderOfType(c, schema, ptrType.Elem()) 75 c.addDecoderToCache(schema.CacheFingerprint(), rtype, decoder) 76 return decoder 77 } 78 79 func decoderOfType(cfg *frozenConfig, schema Schema, typ reflect2.Type) ValDecoder { 80 if dec := createDecoderOfMarshaler(cfg, schema, typ); dec != nil { 81 return dec 82 } 83 84 // Handle eface case when it isnt a union 85 if typ.Kind() == reflect.Interface && schema.Type() != Union { 86 if _, ok := typ.(*reflect2.UnsafeIFaceType); !ok { 87 return newEfaceDecoder(cfg, schema) 88 } 89 } 90 91 switch schema.Type() { 92 case String, Bytes, Int, Long, Float, Double, Boolean: 93 return createDecoderOfNative(schema.(*PrimitiveSchema), typ) 94 95 case Record: 96 return createDecoderOfRecord(cfg, schema, typ) 97 98 case Ref: 99 return decoderOfType(cfg, schema.(*RefSchema).Schema(), typ) 100 101 case Enum: 102 return createDecoderOfEnum(schema, typ) 103 104 case Array: 105 return createDecoderOfArray(cfg, schema, typ) 106 107 case Map: 108 return createDecoderOfMap(cfg, schema, typ) 109 110 case Union: 111 return createDecoderOfUnion(cfg, schema, typ) 112 113 case Fixed: 114 return createDecoderOfFixed(schema, typ) 115 116 default: 117 // It is impossible to get here with a valid schema 118 return &errorDecoder{err: fmt.Errorf("avro: schema type %s is unsupported", schema.Type())} 119 } 120 } 121 122 func (c *frozenConfig) EncoderOf(schema Schema, typ reflect2.Type) ValEncoder { 123 if typ == nil { 124 typ = reflect2.TypeOf((*null)(nil)) 125 } 126 127 rtype := typ.RType() 128 encoder := c.getEncoderFromCache(schema.Fingerprint(), rtype) 129 if encoder != nil { 130 return encoder 131 } 132 133 encoder = encoderOfType(c, schema, typ) 134 if typ.LikePtr() { 135 encoder = &onePtrEncoder{encoder} 136 } 137 c.addEncoderToCache(schema.Fingerprint(), rtype, encoder) 138 return encoder 139 } 140 141 type onePtrEncoder struct { 142 enc ValEncoder 143 } 144 145 func (e *onePtrEncoder) Encode(ptr unsafe.Pointer, w *Writer) { 146 e.enc.Encode(noescape(unsafe.Pointer(&ptr)), w) 147 } 148 149 func encoderOfType(cfg *frozenConfig, schema Schema, typ reflect2.Type) ValEncoder { 150 if enc := createEncoderOfMarshaler(cfg, schema, typ); enc != nil { 151 return enc 152 } 153 154 if typ.Kind() == reflect.Interface { 155 return &interfaceEncoder{schema: schema, typ: typ} 156 } 157 158 switch schema.Type() { 159 case String, Bytes, Int, Long, Float, Double, Boolean, Null: 160 return createEncoderOfNative(schema, typ) 161 162 case Record: 163 return createEncoderOfRecord(cfg, schema, typ) 164 165 case Ref: 166 return encoderOfType(cfg, schema.(*RefSchema).Schema(), typ) 167 168 case Enum: 169 return createEncoderOfEnum(schema, typ) 170 171 case Array: 172 return createEncoderOfArray(cfg, schema, typ) 173 174 case Map: 175 return createEncoderOfMap(cfg, schema, typ) 176 177 case Union: 178 return createEncoderOfUnion(cfg, schema, typ) 179 180 case Fixed: 181 return createEncoderOfFixed(schema, typ) 182 183 default: 184 // It is impossible to get here with a valid schema 185 return &errorEncoder{err: fmt.Errorf("avro: schema type %s is unsupported", schema.Type())} 186 } 187 } 188 189 type errorDecoder struct { 190 err error 191 } 192 193 func (d *errorDecoder) Decode(_ unsafe.Pointer, r *Reader) { 194 if r.Error == nil { 195 r.Error = d.err 196 } 197 } 198 199 type errorEncoder struct { 200 err error 201 } 202 203 func (e *errorEncoder) Encode(_ unsafe.Pointer, w *Writer) { 204 if w.Error == nil { 205 w.Error = e.err 206 } 207 }