github.com/aacfactory/avro@v1.2.12/internal/base/reader_generic.go (about)

     1  package base
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"time"
     7  )
     8  
     9  // ReadNext reads the next Avro element as a generic interface.
    10  func (r *Reader) ReadNext(schema Schema) any {
    11  	var ls LogicalSchema
    12  	lts, ok := schema.(LogicalTypeSchema)
    13  	if ok {
    14  		ls = lts.Logical()
    15  	}
    16  
    17  	switch schema.Type() {
    18  	case Boolean:
    19  		return r.ReadBool()
    20  	case Int:
    21  		if ls != nil {
    22  			switch ls.Type() {
    23  			case Date:
    24  				i := r.ReadInt()
    25  				sec := int64(i) * int64(24*time.Hour/time.Second)
    26  				return time.Unix(sec, 0).UTC()
    27  
    28  			case TimeMillis:
    29  				return time.Duration(r.ReadInt()) * time.Millisecond
    30  			}
    31  		}
    32  		return int(r.ReadInt())
    33  	case Long:
    34  		if ls != nil {
    35  			switch ls.Type() {
    36  			case TimeMicros:
    37  				return time.Duration(r.ReadLong()) * time.Microsecond
    38  
    39  			case TimestampMillis:
    40  				i := r.ReadLong()
    41  				sec := i / 1e3
    42  				nsec := (i - sec*1e3) * 1e6
    43  				return time.Unix(sec, nsec).UTC()
    44  
    45  			case TimestampMicros:
    46  				i := r.ReadLong()
    47  				sec := i / 1e6
    48  				nsec := (i - sec*1e6) * 1e3
    49  				return time.Unix(sec, nsec).UTC()
    50  			}
    51  		}
    52  		return r.ReadLong()
    53  	case Float:
    54  		return r.ReadFloat()
    55  	case Double:
    56  		return r.ReadDouble()
    57  	case String:
    58  		return r.ReadString()
    59  	case Bytes:
    60  		if ls != nil && ls.Type() == Decimal {
    61  			dec := ls.(*DecimalLogicalSchema)
    62  			return ratFromBytes(r.ReadBytes(), dec.Scale())
    63  		}
    64  		return r.ReadBytes()
    65  	case Record:
    66  		fields := schema.(*RecordSchema).Fields()
    67  		obj := make(map[string]any, len(fields))
    68  		for _, field := range fields {
    69  			obj[field.Name()] = r.ReadNext(field.Type())
    70  		}
    71  		return obj
    72  	case Ref:
    73  		return r.ReadNext(schema.(*RefSchema).Schema())
    74  	case Enum:
    75  		symbols := schema.(*EnumSchema).Symbols()
    76  		idx := int(r.ReadInt())
    77  		if idx < 0 || idx >= len(symbols) {
    78  			r.ReportError("Read", "unknown enum symbol")
    79  			return nil
    80  		}
    81  		return symbols[idx]
    82  	case Array:
    83  		arr := []any{}
    84  		r.ReadArrayCB(func(r *Reader) bool {
    85  			elem := r.ReadNext(schema.(*ArraySchema).Items())
    86  			arr = append(arr, elem)
    87  			return true
    88  		})
    89  		return arr
    90  	case Map:
    91  		obj := map[string]any{}
    92  		r.ReadMapCB(func(r *Reader, field string) bool {
    93  			elem := r.ReadNext(schema.(*MapSchema).Values())
    94  			obj[field] = elem
    95  			return true
    96  		})
    97  		return obj
    98  	case Union:
    99  		types := schema.(*UnionSchema).Types()
   100  		idx := int(r.ReadLong())
   101  		if idx < 0 || idx > len(types)-1 {
   102  			r.ReportError("Read", "unknown union type")
   103  			return nil
   104  		}
   105  		schema = types[idx]
   106  		if schema.Type() == Null {
   107  			return nil
   108  		}
   109  
   110  		key := schemaTypeName(schema)
   111  		obj := map[string]any{}
   112  		obj[key] = r.ReadNext(types[idx])
   113  		return obj
   114  	case Fixed:
   115  		size := schema.(*FixedSchema).Size()
   116  		obj := make([]byte, size)
   117  		r.Read(obj)
   118  		if ls != nil && ls.Type() == Decimal {
   119  			dec := ls.(*DecimalLogicalSchema)
   120  			return ratFromBytes(obj, dec.Scale())
   121  		}
   122  		return byteSliceToArray(obj, size)
   123  	default:
   124  		r.ReportError("Read", fmt.Sprintf("unexpected schema type: %v", schema.Type()))
   125  		return nil
   126  	}
   127  }
   128  
   129  // ReadArrayCB reads an array with a callback per item.
   130  func (r *Reader) ReadArrayCB(fn func(*Reader) bool) {
   131  	for {
   132  		l, _ := r.ReadBlockHeader()
   133  		if l == 0 {
   134  			break
   135  		}
   136  		for i := 0; i < int(l); i++ {
   137  			fn(r)
   138  		}
   139  	}
   140  }
   141  
   142  // ReadMapCB reads an array with a callback per item.
   143  func (r *Reader) ReadMapCB(fn func(*Reader, string) bool) {
   144  	for {
   145  		l, _ := r.ReadBlockHeader()
   146  		if l == 0 {
   147  			break
   148  		}
   149  
   150  		for i := 0; i < int(l); i++ {
   151  			field := r.ReadString()
   152  			fn(r, field)
   153  		}
   154  	}
   155  }
   156  
   157  var byteType = reflect.TypeOf((*byte)(nil)).Elem()
   158  
   159  func byteSliceToArray(b []byte, size int) any {
   160  	vArr := reflect.New(reflect.ArrayOf(size, byteType)).Elem()
   161  	reflect.Copy(vArr, reflect.ValueOf(b))
   162  	return vArr.Interface()
   163  }