This repository has been archived by the owner on Jun 5, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
types.go
146 lines (115 loc) · 3.13 KB
/
types.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package skiff
import (
"reflect"
"github.com/go-faster/errors"
"github.com/go-faster/yt/yson"
)
var (
emptyStructType = reflect.TypeOf(struct{}{})
genericMapType = reflect.TypeOf(map[string]interface{}{})
)
type fieldOp struct {
wt WireType
optional bool // encoded as variant<nothing;T>
unused bool // not present in type
omitempty bool // tagged with omitempty
schemaName string
index []int
}
func unpackSimpleVariant(schema *Schema) (wt WireType, optional bool, err error) {
if schema.Type == TypeVariant8 {
if len(schema.Children) != 2 || schema.Children[0].Type != TypeNothing || !schema.Children[1].Type.IsSimple() {
err = errors.Errorf("unsupported skiff type %v", schema)
return
}
wt = schema.Children[1].Type
optional = true
return
} else {
if len(schema.Children) != 0 || !schema.Type.IsSimple() {
err = errors.Errorf("unsupported skiff type %v", schema)
return
}
wt = schema.Type
optional = false
return
}
}
func checkTypes(typ reflect.Type, wt WireType) error {
if typ.Kind() == reflect.Ptr {
typ = typ.Elem()
}
switch wt {
case TypeYSON32:
return nil
case TypeInt64:
switch typ.Kind() {
case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64:
return nil
}
case TypeUint64:
switch typ.Kind() {
case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return nil
}
case TypeDouble:
switch typ.Kind() {
case reflect.Float32, reflect.Float64:
return nil
}
case TypeBoolean:
if typ.Kind() == reflect.Bool {
return nil
}
case TypeString32:
if typ.Kind() == reflect.String {
return nil
}
if typ == reflect.TypeOf([]byte{}) {
return nil
}
}
return errors.Errorf("type %v is not compatible with wire type %s", typ, wt)
}
// skiff encoding and decoding is always driven by the schema. newTranscoder generates
// table describing necessary steps, that must be taken in order to decodeStruct or encode given struct type.
func newTranscoder(schema *Schema, typ reflect.Type) ([]fieldOp, error) {
var fields []fieldOp
if schema.Type != TypeTuple {
return nil, errors.Errorf("skiff: invalid root type %v", schema.Type)
}
if typ.Kind() != reflect.Struct {
return nil, errors.Errorf("skiff: type %v is not supported at root", typ)
}
fieldByName := map[string]reflect.StructField{}
for i := 0; i < typ.NumField(); i++ {
field := typ.Field(i)
tag, skip := yson.ParseTag(field.Name, field.Tag)
if skip {
continue
}
fieldByName[tag.Name] = field
}
var err error
for _, topValue := range schema.Children {
var op fieldOp
op.schemaName = topValue.Name
op.wt, op.optional, err = unpackSimpleVariant(&topValue)
if err != nil {
return nil, errors.Wrapf(err, "skiff: invalid schema for column %q", topValue.Name)
}
field, ok := fieldByName[topValue.Name]
if ok {
tag, _ := yson.ParseTag(field.Name, field.Tag)
if err := checkTypes(field.Type, op.wt); err != nil {
return nil, errors.Wrapf(err, "skiff: invalid schema for column %q", topValue.Name)
}
op.index = field.Index
op.omitempty = tag.Omitempty
} else {
op.unused = true
}
fields = append(fields, op)
}
return fields, nil
}