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  }