package struc import ( "bytes" "encoding/binary" "fmt" "math" "reflect" "unsafe" ) type Field struct { Name string Ptr bool Index int Type Type defType Type Array bool Slice bool Len int Order binary.ByteOrder Sizeof []int Sizefrom []int Fields Fields kind reflect.Kind } func (f *Field) String() string { var out string if f.Type == Pad { return fmt.Sprintf("{type: Pad, len: %d}", f.Len) } else { out = fmt.Sprintf("type: %s, order: %v", f.Type.String(), f.Order) } if f.Sizefrom != nil { out += fmt.Sprintf(", sizefrom: %v", f.Sizefrom) } else if f.Len > 0 { out += fmt.Sprintf(", len: %d", f.Len) } if f.Sizeof != nil { out += fmt.Sprintf(", sizeof: %v", f.Sizeof) } return "{" + out + "}" } func (f *Field) Size(val reflect.Value, options *Options) int { typ := f.Type.Resolve(options) size := 0 if typ == Struct { vals := []reflect.Value{val} if f.Slice { vals = make([]reflect.Value, val.Len()) for i := 0; i < val.Len(); i++ { vals[i] = val.Index(i) } } for _, val := range vals { size += f.Fields.Sizeof(val, options) } } else if typ == Pad { size = f.Len } else if typ == CustomType { return val.Addr().Interface().(Custom).Size(options) } else if f.Slice || f.kind == reflect.String { length := val.Len() if f.Len > 1 { length = f.Len } size = length * typ.Size() } else { size = typ.Size() } align := options.ByteAlign if align > 0 && size < align { size = align } return size } // 预定义常用的order,避免重复判断 var defaultOrder = binary.BigEndian // packVal 优化版:减少反射开销+优化内存拷贝+优雅错误处理 func (f *Field) packVal(buf []byte, val reflect.Value, _ int, options *Options) (size int, err error) { // 1. 预缓存order,避免重复判断 order := f.Order if options != nil && options.Order != nil { order = options.Order } if order == nil { order = defaultOrder } // 2. 处理指针类型:提前解引用,避免后续重复操作 if f.Ptr { if !val.IsNil() { val = val.Elem() } else { return 0, fmt.Errorf("field %s is nil pointer", f.Name) } } // 3. 预解析类型,避免重复Resolve typ := f.Type.Resolve(options) kind := val.Kind() // 4. 扁平化分支逻辑,减少嵌套 switch typ { case Struct: return f.Fields.Pack(buf, val, options) case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64: size = typ.Size() if len(buf) < size { return 0, fmt.Errorf("buf size %d < required %d", len(buf), size) } var n uint64 switch kind { case reflect.Bool: n = boolToUint64(val.Bool()) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: n = uint64(val.Int()) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: n = val.Uint() default: return 0, fmt.Errorf("unsupported kind %s for numeric type %s", kind, typ) } // 扁平化数值写入逻辑 switch typ { case Bool: buf[0] = byte(n) case Int8, Uint8: buf[0] = byte(n) case Int16, Uint16: order.PutUint16(buf, uint16(n)) case Int32, Uint32: order.PutUint32(buf, uint32(n)) case Int64, Uint64: order.PutUint64(buf, n) } case Float32, Float64: size = typ.Size() if len(buf) < size { return 0, fmt.Errorf("buf size %d < required %d", len(buf), size) } if kind != reflect.Float32 && kind != reflect.Float64 { return 0, fmt.Errorf("unsupported kind %s for float type %s", kind, typ) } n := val.Float() switch typ { case Float32: order.PutUint32(buf, math.Float32bits(float32(n))) case Float64: order.PutUint64(buf, math.Float64bits(n)) } case String: // 优化String类型:减少内存拷贝 switch kind { case reflect.String: s := val.String() size = len(s) if len(buf) < size { return 0, fmt.Errorf("buf size %d < string length %d", len(buf), size) } // 用unsafe直接拷贝字符串到buf,避免[]byte(s)的内存分配 copyStringToBuf(buf, s) case reflect.Slice: if val.Type().Elem().Kind() != reflect.Uint8 { return 0, fmt.Errorf("unsupported slice type %s for String field", val.Type()) } size = val.Len() if len(buf) < size { return 0, fmt.Errorf("buf size %d < bytes length %d", len(buf), size) } // 直接拷贝字节切片,避免冗余操作 copy(buf, val.Bytes()) default: return 0, fmt.Errorf("unsupported kind %s for String type", kind) } case CustomType: // 优化反射断言:提前检查类型,避免panic if !val.CanAddr() { return 0, fmt.Errorf("custom type %s cannot take address", val.Type()) } custom, ok := val.Addr().Interface().(Custom) if !ok { return 0, fmt.Errorf("type %s does not implement Custom interface", val.Type()) } return custom.Pack(buf, options) default: // 替换panic为error,避免程序崩溃 return 0, fmt.Errorf("no pack handler for type: %s", typ) } return size, nil } // 辅助函数:bool转uint64,减少inline重复代码 func boolToUint64(b bool) uint64 { if b { return 1 } return 0 } // 辅助函数:unsafe拷贝字符串到buf,避免[]byte(s)的内存分配 // 注意:仅在确定buf长度足够时使用 func copyStringToBuf(buf []byte, s string) { // unsafe转换:字符串转字节切片,无内存分配 src := *(*[]byte)(unsafe.Pointer(&struct { string cap int }{s, len(s)})) copy(buf, src) } func (f *Field) Pack(buf []byte, val reflect.Value, length int, options *Options) (int, error) { typ := f.Type.Resolve(options) if typ == Pad { for i := 0; i < length; i++ { buf[i] = 0 } return length, nil } if f.Slice { // special case strings and byte slices for performance end := val.Len() if !f.Array && typ == Uint8 && (f.defType == Uint8 || f.kind == reflect.String) { var tmp []byte if f.kind == reflect.String { tmp = []byte(val.String()) } else { tmp = val.Bytes() } copy(buf, tmp) if end < length { // TODO: allow configuring pad byte? rep := bytes.Repeat([]byte{0}, length-end) copy(buf[end:], rep) return length, nil } else { copy(buf, buf[:length]) return length, nil } } pos := 0 var zero reflect.Value if end < length { zero = reflect.Zero(val.Type().Elem()) } for i := 0; i < length; i++ { cur := zero if i < end { cur = val.Index(i) } if n, err := f.packVal(buf[pos:], cur, 1, options); err != nil { return pos, err } else { pos += n } } return pos, nil } else { return f.packVal(buf, val, length, options) } } func (f *Field) unpackVal(buf []byte, val reflect.Value, _ int, options *Options) error { order := f.Order if options.Order != nil { order = options.Order } if f.Ptr { val = val.Elem() } typ := f.Type.Resolve(options) switch typ { case Float32, Float64: var n float64 switch typ { case Float32: n = float64(math.Float32frombits(order.Uint32(buf))) case Float64: n = math.Float64frombits(order.Uint64(buf)) } switch f.kind { case reflect.Float32, reflect.Float64: val.SetFloat(n) default: return fmt.Errorf("struc: refusing to unpack float into field %s of type %s", f.Name, f.kind.String()) } case Bool, Int8, Int16, Int32, Int64, Uint8, Uint16, Uint32, Uint64: var n uint64 switch typ { case Int8: n = uint64(int64(int8(buf[0]))) case Int16: n = uint64(int64(int16(order.Uint16(buf)))) case Int32: n = uint64(int64(int32(order.Uint32(buf)))) case Int64: n = uint64(int64(order.Uint64(buf))) case Bool, Uint8: n = uint64(buf[0]) case Uint16: n = uint64(order.Uint16(buf)) case Uint32: n = uint64(order.Uint32(buf)) case Uint64: n = uint64(order.Uint64(buf)) } switch f.kind { case reflect.Bool: val.SetBool(n != 0) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: val.SetInt(int64(n)) default: val.SetUint(n) } default: panic(fmt.Sprintf("no unpack handler for type: %s", typ)) } return nil } func (f *Field) Unpack(buf []byte, val reflect.Value, length int, options *Options) error { typ := f.Type.Resolve(options) if typ == Pad || f.kind == reflect.String { if typ == Pad { return nil } else { val.SetString(string(buf)) return nil } } else if f.Slice { if val.Cap() < length { val.Set(reflect.MakeSlice(val.Type(), length, length)) } else if val.Len() < length { val.Set(val.Slice(0, length)) } // special case byte slices for performance if !f.Array && typ == Uint8 && f.defType == Uint8 { copy(val.Bytes(), buf[:length]) return nil } pos := 0 size := typ.Size() for i := 0; i < length; i++ { if err := f.unpackVal(buf[pos:pos+size], val.Index(i), 1, options); err != nil { return err } pos += size } return nil } else { return f.unpackVal(buf, val, length, options) } }