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 }