diff options
author | Luke Shumaker <lukeshu@lukeshu.com> | 2022-07-10 13:18:30 -0600 |
---|---|---|
committer | Luke Shumaker <lukeshu@lukeshu.com> | 2022-07-10 13:35:20 -0600 |
commit | 27401b6ea459921a6152ab1744da1618358465f4 (patch) | |
tree | 2c4f9c096f1a593e65d7f824901e815ca48bfaf0 /lib/binstruct/size.go | |
parent | 42f6f78e0a32ba0eda707154f8e1ffb4579604ee (diff) |
Rename the module, mv pkg lib
Diffstat (limited to 'lib/binstruct/size.go')
-rw-r--r-- | lib/binstruct/size.go | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/lib/binstruct/size.go b/lib/binstruct/size.go new file mode 100644 index 0000000..6563455 --- /dev/null +++ b/lib/binstruct/size.go @@ -0,0 +1,57 @@ +package binstruct + +import ( + "fmt" + "reflect" +) + +type StaticSizer interface { + BinaryStaticSize() int +} + +func StaticSize(obj any) int { + sz, err := staticSize(reflect.TypeOf(obj)) + if err != nil { + panic(err) + } + return sz +} + +var ( + staticSizerType = reflect.TypeOf((*StaticSizer)(nil)).Elem() + marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() + unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() +) + +func staticSize(typ reflect.Type) (int, error) { + if typ.Implements(staticSizerType) { + return reflect.New(typ).Elem().Interface().(StaticSizer).BinaryStaticSize(), nil + } + switch typ.Kind() { + case reflect.Uint8, reflect.Int8: + return 1, nil + case reflect.Uint16, reflect.Int16: + return 2, nil + case reflect.Uint32, reflect.Int32: + return 4, nil + case reflect.Uint64, reflect.Int64: + return 8, nil + case reflect.Ptr: + return staticSize(typ.Elem()) + case reflect.Array: + elemSize, err := staticSize(typ.Elem()) + if err != nil { + return 0, err + } + return elemSize * typ.Len(), nil + case reflect.Struct: + if !(typ.Implements(marshalerType) || typ.Implements(unmarshalerType)) { + return getStructHandler(typ).Size, nil + } + return 0, fmt.Errorf("type=%v (kind=%v) does not implement binfmt.StaticSizer but does implement binfmt.Marshaler or binfmt.Unmarshaler", + typ, typ.Kind()) + default: + return 0, fmt.Errorf("type=%v does not implement binfmt.StaticSizer and kind=%v is not a supported statically-sized kind", + typ, typ.Kind()) + } +} |