1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859 |
- package pseudounion
- import "reflect"
- type Tag int
- var tagType = reflect.TypeOf(Tag(0))
- func Load(u interface{}) interface{} {
- var ru = reflect.ValueOf(u)
- if ru.Kind() != reflect.Struct {
- checkKind(ru, reflect.Pointer)
- ru = ru.Elem()
- checkKind(ru, reflect.Struct)
- }
- var index = int(assertTagType(ru.Field(0)).Int())
- if index <= 0 {
- panic("invalid pseudo-union index: zero or negative")
- }
- if index > ru.NumField() {
- panic("invalid pseudo-union index: too big")
- }
- return ru.Field(index).Interface()
- }
- func Store[T any] (v interface{}) T {
- var u T
- var ru = reflect.ValueOf(&u).Elem()
- if ru.Kind() != reflect.Struct {
- checkKind(ru, reflect.Pointer)
- ru.Set(reflect.New(ru.Type().Elem()))
- ru = ru.Elem()
- checkKind(ru, reflect.Struct)
- }
- var rv = reflect.ValueOf(v)
- for i := 1; i < ru.NumField(); i += 1 {
- if rv.Type().AssignableTo(ru.Type().Field(i).Type) {
- ru.Field(i).Set(rv)
- assertTagType(ru.Field(0)).SetInt(int64(i))
- return u
- }
- }
- panic("invalid pseudo-union value: none of fields assignable")
- }
- func checkKind(ru reflect.Value, expected reflect.Kind) {
- if ru.Kind() != expected {
- panic("invalid pseudo-union type: " + ru.Type().String())
- }
- }
- func assertTagType(rv reflect.Value) reflect.Value {
- if rv.Type() != tagType {
- panic("invalid pseudo-union")
- }
- return rv
- }
|