gitee.com/quant1x/gox@v1.21.2/encoding/binary/struc/field.go (about)

     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  }