1
2
3
4
5
6
7
8
9
10
11
12 package bitfield
13
14 import (
15 "bytes"
16 "fmt"
17 "io"
18 "reflect"
19 "strconv"
20 "strings"
21 )
22
23
24
25 type Config struct {
26
27
28
29 NumBits uint
30
31
32 Package string
33
34
35
36 TypeName string
37 }
38
39 var nullConfig = &Config{}
40
41
42
43
44 func Pack(x interface{}, c *Config) (packed uint64, err error) {
45 packed, _, err = pack(x, c)
46 return
47 }
48
49 func pack(x interface{}, c *Config) (packed uint64, nBit uint, err error) {
50 if c == nil {
51 c = nullConfig
52 }
53 nBits := c.NumBits
54 v := reflect.ValueOf(x)
55 v = reflect.Indirect(v)
56 t := v.Type()
57 pos := 64 - nBits
58 if nBits == 0 {
59 pos = 0
60 }
61 for i := 0; i < v.NumField(); i++ {
62 v := v.Field(i)
63 field := t.Field(i)
64 f, err := parseField(field)
65
66 if err != nil {
67 return 0, 0, err
68 }
69 if f.nBits == 0 {
70 continue
71 }
72 value := uint64(0)
73 switch v.Kind() {
74 case reflect.Bool:
75 if v.Bool() {
76 value = 1
77 }
78 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
79 value = v.Uint()
80 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
81 x := v.Int()
82 if x < 0 {
83 return 0, 0, fmt.Errorf("bitfield: negative value for field %q not allowed", field.Name)
84 }
85 value = uint64(x)
86 }
87 if value > (1<<f.nBits)-1 {
88 return 0, 0, fmt.Errorf("bitfield: value %#x of field %q does not fit in %d bits", value, field.Name, f.nBits)
89 }
90 shift := 64 - pos - f.nBits
91 if pos += f.nBits; pos > 64 {
92 return 0, 0, fmt.Errorf("bitfield: no more bits left for field %q", field.Name)
93 }
94 packed |= value << shift
95 }
96 if nBits == 0 {
97 nBits = posToBits(pos)
98 packed >>= (64 - nBits)
99 }
100 return packed, nBits, nil
101 }
102
103 type field struct {
104 name string
105 value uint64
106 nBits uint
107 }
108
109
110 func parseField(field reflect.StructField) (f field, err error) {
111 s, ok := field.Tag.Lookup("bitfield")
112 if !ok {
113 return f, nil
114 }
115 switch field.Type.Kind() {
116 case reflect.Bool:
117 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
118 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
119 default:
120 return f, fmt.Errorf("bitfield: field %q is not an integer or bool type", field.Name)
121 }
122 bits := s
123 f.name = ""
124
125 if i := strings.IndexByte(s, ','); i >= 0 {
126 bits = s[:i]
127 f.name = s[i+1:]
128 }
129 if bits != "" {
130 nBits, err := strconv.ParseUint(bits, 10, 8)
131 if err != nil {
132 return f, fmt.Errorf("bitfield: invalid bit size for field %q: %v", field.Name, err)
133 }
134 f.nBits = uint(nBits)
135 }
136 if f.nBits == 0 {
137 if field.Type.Kind() == reflect.Bool {
138 f.nBits = 1
139 } else {
140 f.nBits = uint(field.Type.Bits())
141 }
142 }
143 if f.name == "" {
144 f.name = field.Name
145 }
146 return f, err
147 }
148
149 func posToBits(pos uint) (bits uint) {
150 switch {
151 case pos <= 8:
152 bits = 8
153 case pos <= 16:
154 bits = 16
155 case pos <= 32:
156 bits = 32
157 case pos <= 64:
158 bits = 64
159 default:
160 panic("unreachable")
161 }
162 return bits
163 }
164
165
166 func Gen(w io.Writer, x interface{}, c *Config) error {
167 if c == nil {
168 c = nullConfig
169 }
170 _, nBits, err := pack(x, c)
171 if err != nil {
172 return err
173 }
174
175 t := reflect.TypeOf(x)
176 if t.Kind() == reflect.Ptr {
177 t = t.Elem()
178 }
179 if c.TypeName == "" {
180 c.TypeName = t.Name()
181 }
182 firstChar := []rune(c.TypeName)[0]
183
184 buf := &bytes.Buffer{}
185
186 print := func(w io.Writer, format string, args ...interface{}) {
187 if _, e := fmt.Fprintf(w, format+"\n", args...); e != nil && err == nil {
188 err = fmt.Errorf("bitfield: write failed: %v", err)
189 }
190 }
191
192 pos := uint(0)
193 for i := 0; i < t.NumField(); i++ {
194 field := t.Field(i)
195 f, _ := parseField(field)
196 if f.nBits == 0 {
197 continue
198 }
199 shift := nBits - pos - f.nBits
200 pos += f.nBits
201
202 retType := field.Type.Name()
203 print(buf, "\nfunc (%c %s) %s() %s {", firstChar, c.TypeName, f.name, retType)
204 if field.Type.Kind() == reflect.Bool {
205 print(buf, "\tconst bit = 1 << %d", shift)
206 print(buf, "\treturn %c&bit == bit", firstChar)
207 } else {
208 print(buf, "\treturn %s((%c >> %d) & %#x)", retType, firstChar, shift, (1<<f.nBits)-1)
209 }
210 print(buf, "}")
211 }
212
213 if c.Package != "" {
214 print(w, "// Code generated by golang.org/x/text/internal/gen/bitfield. DO NOT EDIT.\n")
215 print(w, "package %s\n", c.Package)
216 }
217
218 bits := posToBits(pos)
219
220 print(w, "type %s uint%d", c.TypeName, bits)
221
222 if _, err := io.Copy(w, buf); err != nil {
223 return fmt.Errorf("bitfield: write failed: %v", err)
224 }
225 return nil
226 }
227
View as plain text