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