gitee.com/quant1x/gox@v1.21.2/encoding/binary/struc/struc.go (about) 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 init() { 32 // fill default values to avoid data race to be reported by race detector. 33 emptyOptions.Validate() 34 } 35 36 func prep(data interface{}) (reflect.Value, Packer, error) { 37 value := reflect.ValueOf(data) 38 for value.Kind() == reflect.Ptr { 39 next := value.Elem().Kind() 40 if next == reflect.Struct || next == reflect.Ptr { 41 value = value.Elem() 42 } else { 43 break 44 } 45 } 46 switch value.Kind() { 47 case reflect.Struct: 48 fields, err := parseFields(value) 49 return value, fields, err 50 default: 51 if !value.IsValid() { 52 return reflect.Value{}, nil, fmt.Errorf("Invalid reflect.Value for %+v", data) 53 } 54 if c, ok := data.(Custom); ok { 55 return value, customFallback{c}, nil 56 } 57 return value, binaryFallback(value), nil 58 } 59 } 60 61 func Pack(w io.Writer, data interface{}) error { 62 return PackWithOptions(w, data, nil) 63 } 64 65 func PackWithOptions(w io.Writer, data interface{}, options *Options) error { 66 if options == nil { 67 options = emptyOptions 68 } 69 if err := options.Validate(); err != nil { 70 return err 71 } 72 val, packer, err := prep(data) 73 if err != nil { 74 return err 75 } 76 if val.Type().Kind() == reflect.String { 77 val = val.Convert(reflect.TypeOf([]byte{})) 78 } 79 size := packer.Sizeof(val, options) 80 buf := make([]byte, size) 81 if _, err := packer.Pack(buf, val, options); err != nil { 82 return err 83 } 84 _, err = w.Write(buf) 85 return err 86 } 87 88 func Unpack(r io.Reader, data interface{}) error { 89 return UnpackWithOptions(r, data, nil) 90 } 91 92 func UnpackWithOptions(r io.Reader, data interface{}, options *Options) error { 93 if options == nil { 94 options = emptyOptions 95 } 96 if err := options.Validate(); err != nil { 97 return err 98 } 99 val, packer, err := prep(data) 100 if err != nil { 101 return err 102 } 103 return packer.Unpack(r, val, options) 104 } 105 106 func Sizeof(data interface{}) (int, error) { 107 return SizeofWithOptions(data, nil) 108 } 109 110 func SizeofWithOptions(data interface{}, options *Options) (int, error) { 111 if options == nil { 112 options = emptyOptions 113 } 114 if err := options.Validate(); err != nil { 115 return 0, err 116 } 117 val, packer, err := prep(data) 118 if err != nil { 119 return 0, err 120 } 121 return packer.Sizeof(val, options), nil 122 }