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  }