initial commit
[govpp.git] / vendor / github.com / lunixbochs / struc / struc.go
1 package struc
2
3 import (
4         "encoding/binary"
5         "fmt"
6         "io"
7         "reflect"
8 )
9
10 type Options struct {
11         ByteAlign int
12         PtrSize   int
13         Order     binary.ByteOrder
14 }
15
16 func (o *Options) Validate() error {
17         if o.PtrSize == 0 {
18                 o.PtrSize = 32
19         } else {
20                 switch o.PtrSize {
21                 case 8, 16, 32, 64:
22                 default:
23                         return fmt.Errorf("Invalid Options.PtrSize: %d. Must be in (8, 16, 32, 64)", o.PtrSize)
24                 }
25         }
26         return nil
27 }
28
29 var emptyOptions = &Options{}
30
31 func prep(data interface{}) (reflect.Value, Packer, error) {
32         value := reflect.ValueOf(data)
33         for value.Kind() == reflect.Ptr {
34                 next := value.Elem().Kind()
35                 if next == reflect.Struct || next == reflect.Ptr {
36                         value = value.Elem()
37                 } else {
38                         break
39                 }
40         }
41         switch value.Kind() {
42         case reflect.Struct:
43                 fields, err := parseFields(value)
44                 return value, fields, err
45         default:
46                 if !value.IsValid() {
47                         return reflect.Value{}, nil, fmt.Errorf("Invalid reflect.Value for %+v", data)
48                 }
49                 if c, ok := data.(Custom); ok {
50                         return value, customFallback{c}, nil
51                 }
52                 return value, binaryFallback(value), nil
53         }
54 }
55
56 func Pack(w io.Writer, data interface{}) error {
57         return PackWithOptions(w, data, nil)
58 }
59
60 func PackWithOptions(w io.Writer, data interface{}, options *Options) error {
61         if options == nil {
62                 options = emptyOptions
63         }
64         if err := options.Validate(); err != nil {
65                 return err
66         }
67         val, packer, err := prep(data)
68         if err != nil {
69                 return err
70         }
71         if val.Type().Kind() == reflect.String {
72                 val = val.Convert(reflect.TypeOf([]byte{}))
73         }
74         size := packer.Sizeof(val, options)
75         buf := make([]byte, size)
76         if _, err := packer.Pack(buf, val, options); err != nil {
77                 return err
78         }
79         _, err = w.Write(buf)
80         return err
81 }
82
83 func Unpack(r io.Reader, data interface{}) error {
84         return UnpackWithOptions(r, data, nil)
85 }
86
87 func UnpackWithOptions(r io.Reader, data interface{}, options *Options) error {
88         if options == nil {
89                 options = emptyOptions
90         }
91         if err := options.Validate(); err != nil {
92                 return err
93         }
94         val, packer, err := prep(data)
95         if err != nil {
96                 return err
97         }
98         return packer.Unpack(r, val, options)
99 }
100
101 func Sizeof(data interface{}) (int, error) {
102         return SizeofWithOptions(data, nil)
103 }
104
105 func SizeofWithOptions(data interface{}, options *Options) (int, error) {
106         if options == nil {
107                 options = emptyOptions
108         }
109         if err := options.Validate(); err != nil {
110                 return 0, err
111         }
112         val, packer, err := prep(data)
113         if err != nil {
114                 return 0, err
115         }
116         return packer.Sizeof(val, options), nil
117 }