-
Notifications
You must be signed in to change notification settings - Fork 0
/
field.go
141 lines (125 loc) · 2.7 KB
/
field.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
package packet
import (
"fmt"
"reflect"
"strconv"
"strings"
)
// ValueFields is an array of fields
type valueFields []*field
var _structFields map[string]*valueFields
func init() {
_structFields = make(map[string]*valueFields)
}
const tagName = "packet"
type unit uint
const (
_bits unit = iota
_byte
)
func (u unit) String() string {
switch u {
case _bits:
return "b"
case _byte:
return "B"
}
return "uncognized unit(" + string(int(u)) + ")"
}
type length struct {
unit unit
length uint64
}
func (l *length) String() string {
return fmt.Sprintf("%d%s", l.length, l.unit)
}
type when struct {
field string
condition string
value uint64
}
type field struct {
reflect.StructField
length *length
when *when
lengthfrom string
countfrom string
f struct {
lengthfor bool
lengthrest bool
}
}
func getStructFields(v reflect.Value) *valueFields {
if v.Kind() != reflect.Struct {
panic(fmt.Errorf("%s not a struct", v.Kind()))
}
vf, ok := _structFields[v.Type().Name()]
if !ok {
vf = &valueFields{}
t := v.Type()
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
*vf = append(*vf, newField(f))
}
_structFields[v.Type().Name()] = vf
}
return vf
}
func newField(_f reflect.StructField) *field {
f := &field{StructField: _f}
f.populateTag()
return f
}
func (f *field) populateTag() {
tags := f.Tag.Get(tagName)
if tags == "" {
return
}
for _, tag := range strings.Split(tags, ",") {
head := tag
if equalAt := strings.Index(tag, "="); equalAt != -1 {
head = tag[0:equalAt]
value := tag[equalAt+1:]
switch head {
case "length":
u, err := strconv.ParseUint(value[0:len(value)-1], 10, 64)
if err != nil {
panic(fmt.Errorf("failed to parse length (%s)", value))
}
switch value[len(value)-1] {
case 'b':
f.length = &length{unit: _bits, length: u}
case 'B':
f.length = &length{unit: _byte, length: u}
default:
panic(fmt.Errorf("not handling unit spec (%s)", value))
}
case "when":
c := strings.Split(value, "-")
if len(c) != 3 {
panic(fmt.Errorf("(when) should have 3 words seprated by (-), but got %s", value))
}
v, err := strconv.ParseUint(c[2], 10, 32)
if err != nil {
panic(fmt.Errorf("failed to parse: %s", err))
}
f.when = &when{field: c[0], condition: c[1], value: v}
case "lengthfrom":
f.lengthfrom = value
case "countfrom":
f.countfrom = value
default:
panic(fmt.Errorf("unrecogned header (%s)", head))
}
} else {
switch head {
case "lengthfor":
f.f.lengthfor = true
case "lengthrest":
f.f.lengthrest = true
default:
panic(fmt.Errorf("unrecogned header (%s) tags (%s)", head, tags))
}
}
}
}