13 func (f Fields) SetByteOrder(order binary.ByteOrder) {
14 for _, field := range f {
19 func (f Fields) String() string {
20 fields := make([]string, len(f))
21 for i, field := range f {
22 fields[i] = field.String()
24 return "{" + strings.Join(fields, ", ") + "}"
27 func (f Fields) Sizeof(val reflect.Value, options *Options) int {
28 for val.Kind() == reflect.Ptr {
32 for i, field := range f {
35 size += field.Size(v, options)
41 func (f Fields) sizefrom(val reflect.Value, index []int) int {
42 field := val.FieldByIndex(index)
44 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
45 return int(field.Int())
46 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
47 n := int(field.Uint())
48 // all the builtin array length types are native int
49 // so this guards against weird truncation
55 name := val.Type().FieldByIndex(index).Name
56 panic(fmt.Sprintf("sizeof field %T.%s not an integer type", val.Interface(), name))
60 func (f Fields) Pack(buf []byte, val reflect.Value, options *Options) (int, error) {
61 for val.Kind() == reflect.Ptr {
65 for i, field := range f {
71 if field.Sizefrom != nil {
72 length = f.sizefrom(val, field.Sizefrom)
74 if length <= 0 && field.Slice {
77 if field.Sizeof != nil {
78 length := val.FieldByIndex(field.Sizeof).Len()
80 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
81 // allocating a new int here has fewer side effects (doesn't update the original struct)
82 // but it's a wasteful allocation
83 // the old method might work if we just cast the temporary int/uint to the target type
84 v = reflect.New(v.Type()).Elem()
85 v.SetInt(int64(length))
86 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
87 v = reflect.New(v.Type()).Elem()
88 v.SetUint(uint64(length))
90 panic(fmt.Sprintf("sizeof field is not int or uint type: %s, %s", field.Name, v.Type()))
93 if n, err := field.Pack(buf[pos:], v, length, options); err != nil {
102 func (f Fields) Unpack(r io.Reader, val reflect.Value, options *Options) error {
103 for val.Kind() == reflect.Ptr {
108 for i, field := range f {
114 if field.Sizefrom != nil {
115 length = f.sizefrom(val, field.Sizefrom)
117 if v.Kind() == reflect.Ptr && !v.Elem().IsValid() {
118 v.Set(reflect.New(v.Type().Elem()))
120 if field.Type == Struct {
122 vals := reflect.MakeSlice(v.Type(), length, length)
123 for i := 0; i < length; i++ {
125 fields, err := parseFields(v)
129 if err := fields.Unpack(r, v, options); err != nil {
135 // TODO: DRY (we repeat the inner loop above)
136 fields, err := parseFields(v)
140 if err := fields.Unpack(r, v, options); err != nil {
146 typ := field.Type.Resolve(options)
147 if typ == CustomType {
148 if err := v.Addr().Interface().(Custom).Unpack(r, length, options); err != nil {
152 size := length * field.Type.Resolve(options).Size()
156 buf = make([]byte, size)
158 if _, err := io.ReadFull(r, buf); err != nil {
161 err := field.Unpack(buf[:size], v, length, options)