initial commit
[govpp.git] / vendor / github.com / lunixbochs / struc / field.go
1 package struc
2
3 import (
4         "bytes"
5         "encoding/binary"
6         "fmt"
7         "math"
8         "reflect"
9 )
10
11 type Field struct {
12         Name     string
13         CanSet   bool
14         Ptr      bool
15         Index    int
16         Type     Type
17         defType  Type
18         Array    bool
19         Slice    bool
20         Len      int
21         Order    binary.ByteOrder
22         Sizeof   []int
23         Sizefrom []int
24         Fields   Fields
25         kind     reflect.Kind
26 }
27
28 func (f *Field) String() string {
29         var out string
30         if f.Type == Pad {
31                 return fmt.Sprintf("{type: Pad, len: %d}", f.Len)
32         } else {
33                 out = fmt.Sprintf("type: %s, order: %v", f.Type.String(), f.Order)
34         }
35         if f.Sizefrom != nil {
36                 out += fmt.Sprintf(", sizefrom: %v", f.Sizefrom)
37         } else if f.Len > 0 {
38                 out += fmt.Sprintf(", len: %d", f.Len)
39         }
40         if f.Sizeof != nil {
41                 out += fmt.Sprintf(", sizeof: %v", f.Sizeof)
42         }
43         return "{" + out + "}"
44 }
45
46 func (f *Field) Size(val reflect.Value, options *Options) int {
47         typ := f.Type.Resolve(options)
48         size := 0
49         if typ == Struct {
50                 vals := []reflect.Value{val}
51                 if f.Slice {
52                         vals = make([]reflect.Value, val.Len())
53                         for i := 0; i < val.Len(); i++ {
54                                 vals[i] = val.Index(i)
55                         }
56                 }
57                 for _, val := range vals {
58                         size += f.Fields.Sizeof(val, options)
59                 }
60         } else if typ == Pad {
61                 size = f.Len
62         } else if f.Slice || f.kind == reflect.String {
63                 length := val.Len()
64                 if f.Len > 1 {
65                         length = f.Len
66                 }
67                 size = length * typ.Size()
68         } else if typ == CustomType {
69                 return val.Addr().Interface().(Custom).Size(options)
70         } else {
71                 size = typ.Size()
72         }
73         align := options.ByteAlign
74         if align > 0 && size < align {
75                 size = align
76         }
77         return size
78 }
79
80 func (f *Field) packVal(buf []byte, val reflect.Value, length int, options *Options) (size int, err error) {
81         order := f.Order
82         if options.Order != nil {
83                 order = options.Order
84         }
85         if f.Ptr {
86                 val = val.Elem()
87         }
88         typ := f.Type.Resolve(options)
89         switch typ {
90         case Struct:
91                 return f.Fields.Pack(buf, val, options)
92         case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64:
93                 size = typ.Size()
94                 var n uint64
95                 switch f.kind {
96                 case reflect.Bool:
97                         if val.Bool() {
98                                 n = 1
99                         } else {
100                                 n = 0
101                         }
102                 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
103                         n = uint64(val.Int())
104                 default:
105                         n = val.Uint()
106                 }
107                 switch typ {
108                 case Bool:
109                         if n != 0 {
110                                 buf[0] = 1
111                         } else {
112                                 buf[0] = 0
113                         }
114                 case Int8, Uint8:
115                         buf[0] = byte(n)
116                 case Int16, Uint16:
117                         order.PutUint16(buf, uint16(n))
118                 case Int32, Uint32:
119                         order.PutUint32(buf, uint32(n))
120                 case Int64, Uint64:
121                         order.PutUint64(buf, uint64(n))
122                 }
123         case Float32, Float64:
124                 size = typ.Size()
125                 n := val.Float()
126                 switch typ {
127                 case Float32:
128                         order.PutUint32(buf, math.Float32bits(float32(n)))
129                 case Float64:
130                         order.PutUint64(buf, math.Float64bits(n))
131                 }
132         case String:
133                 switch f.kind {
134                 case reflect.String:
135                         size = val.Len()
136                         copy(buf, []byte(val.String()))
137                 default:
138                         // TODO: handle kind != bytes here
139                         size = val.Len()
140                         copy(buf, val.Bytes())
141                 }
142         case CustomType:
143                 return val.Addr().Interface().(Custom).Pack(buf, options)
144         default:
145                 panic(fmt.Sprintf("no pack handler for type: %s", typ))
146         }
147         return
148 }
149
150 func (f *Field) Pack(buf []byte, val reflect.Value, length int, options *Options) (int, error) {
151         typ := f.Type.Resolve(options)
152         if typ == Pad {
153                 for i := 0; i < length; i++ {
154                         buf[i] = 0
155                 }
156                 return length, nil
157         }
158         if f.Slice {
159                 // special case strings and byte slices for performance
160                 end := val.Len()
161                 if !f.Array && typ == Uint8 && (f.defType == Uint8 || f.kind == reflect.String) {
162                         var tmp []byte
163                         if f.kind == reflect.String {
164                                 tmp = []byte(val.String())
165                         } else {
166                                 tmp = val.Bytes()
167                         }
168                         copy(buf, tmp)
169                         if end < length {
170                                 // TODO: allow configuring pad byte?
171                                 rep := bytes.Repeat([]byte{0}, length-end)
172                                 copy(buf[end:], rep)
173                                 return length, nil
174                         }
175                         return val.Len(), nil
176                 }
177                 pos := 0
178                 var zero reflect.Value
179                 if end < length {
180                         zero = reflect.Zero(val.Type().Elem())
181                 }
182                 for i := 0; i < length; i++ {
183                         cur := zero
184                         if i < end {
185                                 cur = val.Index(i)
186                         }
187                         if n, err := f.packVal(buf[pos:], cur, 1, options); err != nil {
188                                 return pos, err
189                         } else {
190                                 pos += n
191                         }
192                 }
193                 return pos, nil
194         } else {
195                 return f.packVal(buf, val, length, options)
196         }
197 }
198
199 func (f *Field) unpackVal(buf []byte, val reflect.Value, length int, options *Options) error {
200         order := f.Order
201         if options.Order != nil {
202                 order = options.Order
203         }
204         if f.Ptr {
205                 val = val.Elem()
206         }
207         typ := f.Type.Resolve(options)
208         switch typ {
209         case Float32, Float64:
210                 var n float64
211                 switch typ {
212                 case Float32:
213                         n = float64(math.Float32frombits(order.Uint32(buf)))
214                 case Float64:
215                         n = math.Float64frombits(order.Uint64(buf))
216                 }
217                 switch f.kind {
218                 case reflect.Float32, reflect.Float64:
219                         val.SetFloat(n)
220                 default:
221                         return fmt.Errorf("struc: refusing to unpack float into field %s of type %s", f.Name, f.kind.String())
222                 }
223         case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64:
224                 var n uint64
225                 switch typ {
226                 case Bool, Int8, Uint8:
227                         n = uint64(buf[0])
228                 case Int16, Uint16:
229                         n = uint64(order.Uint16(buf))
230                 case Int32, Uint32:
231                         n = uint64(order.Uint32(buf))
232                 case Int64, Uint64:
233                         n = uint64(order.Uint64(buf))
234                 }
235                 switch f.kind {
236                 case reflect.Bool:
237                         val.SetBool(n != 0)
238                 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
239                         val.SetInt(int64(n))
240                 default:
241                         val.SetUint(n)
242                 }
243         default:
244                 panic(fmt.Sprintf("no unpack handler for type: %s", typ))
245         }
246         return nil
247 }
248
249 func (f *Field) Unpack(buf []byte, val reflect.Value, length int, options *Options) error {
250         typ := f.Type.Resolve(options)
251         if typ == Pad || f.kind == reflect.String {
252                 if typ == Pad {
253                         return nil
254                 } else {
255                         val.SetString(string(buf))
256                         return nil
257                 }
258         } else if f.Slice {
259                 if val.Cap() < length {
260                         val.Set(reflect.MakeSlice(val.Type(), length, length))
261                 } else if val.Len() < length {
262                         val.Set(val.Slice(0, length))
263                 }
264                 // special case byte slices for performance
265                 if !f.Array && typ == Uint8 && f.defType == Uint8 {
266                         copy(val.Bytes(), buf[:length])
267                         return nil
268                 }
269                 pos := 0
270                 size := typ.Size()
271                 for i := 0; i < length; i++ {
272                         if err := f.unpackVal(buf[pos:pos+size], val.Index(i), 1, options); err != nil {
273                                 return err
274                         }
275                         pos += size
276                 }
277                 return nil
278         } else {
279                 return f.unpackVal(buf, val, length, options)
280         }
281 }