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