// +build !safe // +build !appengine // +build go1.7 // Copyright (c) 2012-2018 Ugorji Nwoke. All rights reserved. // Use of this source code is governed by a MIT license found in the LICENSE file. package codec import ( "reflect" "sync/atomic" "time" "unsafe" ) // This file has unsafe variants of some helper methods. // NOTE: See helper_not_unsafe.go for the usage information. // var zeroRTv [4]uintptr const safeMode = false const unsafeFlagIndir = 1 << 7 // keep in sync with GO_ROOT/src/reflect/value.go type unsafeString struct { Data unsafe.Pointer Len int } type unsafeSlice struct { Data unsafe.Pointer Len int Cap int } type unsafeIntf struct { typ unsafe.Pointer word unsafe.Pointer } type unsafeReflectValue struct { typ unsafe.Pointer ptr unsafe.Pointer flag uintptr } func stringView(v []byte) string { if len(v) == 0 { return "" } bx := (*unsafeSlice)(unsafe.Pointer(&v)) return *(*string)(unsafe.Pointer(&unsafeString{bx.Data, bx.Len})) } func bytesView(v string) []byte { if len(v) == 0 { return zeroByteSlice } sx := (*unsafeString)(unsafe.Pointer(&v)) return *(*[]byte)(unsafe.Pointer(&unsafeSlice{sx.Data, sx.Len, sx.Len})) } func definitelyNil(v interface{}) bool { // There is no global way of checking if an interface is nil. // For true references (map, ptr, func, chan), you can just look // at the word of the interface. However, for slices, you have to dereference // the word, and get a pointer to the 3-word interface value. // // However, the following are cheap calls // - TypeOf(interface): cheap 2-line call. // - ValueOf(interface{}): expensive // - type.Kind: cheap call through an interface // - Value.Type(): cheap call // except it's a method value (e.g. r.Read, which implies that it is a Func) return ((*unsafeIntf)(unsafe.Pointer(&v))).word == nil } func rv2i(rv reflect.Value) interface{} { // TODO: consider a more generally-known optimization for reflect.Value ==> Interface // // Currently, we use this fragile method that taps into implememtation details from // the source go stdlib reflect/value.go, and trims the implementation. urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) // true references (map, func, chan, ptr - NOT slice) may be double-referenced as flagIndir var ptr unsafe.Pointer if refBitset.isset(byte(urv.flag&(1<<5-1))) && urv.flag&unsafeFlagIndir != 0 { ptr = *(*unsafe.Pointer)(urv.ptr) } else { ptr = urv.ptr } return *(*interface{})(unsafe.Pointer(&unsafeIntf{typ: urv.typ, word: ptr})) } func rt2id(rt reflect.Type) uintptr { return uintptr(((*unsafeIntf)(unsafe.Pointer(&rt))).word) } func rv2rtid(rv reflect.Value) uintptr { return uintptr((*unsafeReflectValue)(unsafe.Pointer(&rv)).typ) } func i2rtid(i interface{}) uintptr { return uintptr(((*unsafeIntf)(unsafe.Pointer(&i))).typ) } // -------------------------- func isEmptyValue(v reflect.Value, tinfos *TypeInfos, deref, checkStruct bool) bool { urv := (*unsafeReflectValue)(unsafe.Pointer(&v)) if urv.flag == 0 { return true } switch v.Kind() { case reflect.Invalid: return true case reflect.String: return (*unsafeString)(urv.ptr).Len == 0 case reflect.Slice: return (*unsafeSlice)(urv.ptr).Len == 0 case reflect.Bool: return !*(*bool)(urv.ptr) case reflect.Int: return *(*int)(urv.ptr) == 0 case reflect.Int8: return *(*int8)(urv.ptr) == 0 case reflect.Int16: return *(*int16)(urv.ptr) == 0 case reflect.Int32: return *(*int32)(urv.ptr) == 0 case reflect.Int64: return *(*int64)(urv.ptr) == 0 case reflect.Uint: return *(*uint)(urv.ptr) == 0 case reflect.Uint8: return *(*uint8)(urv.ptr) == 0 case reflect.Uint16: return *(*uint16)(urv.ptr) == 0 case reflect.Uint32: return *(*uint32)(urv.ptr) == 0 case reflect.Uint64: return *(*uint64)(urv.ptr) == 0 case reflect.Uintptr: return *(*uintptr)(urv.ptr) == 0 case reflect.Float32: return *(*float32)(urv.ptr) == 0 case reflect.Float64: return *(*float64)(urv.ptr) == 0 case reflect.Interface: isnil := urv.ptr == nil || *(*unsafe.Pointer)(urv.ptr) == nil if deref { if isnil { return true } return isEmptyValue(v.Elem(), tinfos, deref, checkStruct) } return isnil case reflect.Ptr: isnil := urv.ptr == nil if deref { if isnil { return true } return isEmptyValue(v.Elem(), tinfos, deref, checkStruct) } return isnil case reflect.Struct: return isEmptyStruct(v, tinfos, deref, checkStruct) case reflect.Map, reflect.Array, reflect.Chan: return v.Len() == 0 } return false } // -------------------------- type atomicTypeInfoSlice struct { // expected to be 2 words v unsafe.Pointer // data array - Pointer (not uintptr) to maintain GC reference l int64 // length of the data array } func (x *atomicTypeInfoSlice) load() []rtid2ti { l := int(atomic.LoadInt64(&x.l)) if l == 0 { return nil } return *(*[]rtid2ti)(unsafe.Pointer(&unsafeSlice{Data: atomic.LoadPointer(&x.v), Len: l, Cap: l})) } func (x *atomicTypeInfoSlice) store(p []rtid2ti) { s := (*unsafeSlice)(unsafe.Pointer(&p)) atomic.StorePointer(&x.v, s.Data) atomic.StoreInt64(&x.l, int64(s.Len)) } // -------------------------- func (d *Decoder) raw(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*[]byte)(urv.ptr) = d.rawBytes() } func (d *Decoder) kString(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*string)(urv.ptr) = d.d.DecodeString() } func (d *Decoder) kBool(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*bool)(urv.ptr) = d.d.DecodeBool() } func (d *Decoder) kTime(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*time.Time)(urv.ptr) = d.d.DecodeTime() } func (d *Decoder) kFloat32(f *codecFnInfo, rv reflect.Value) { fv := d.d.DecodeFloat64() if chkOvf.Float32(fv) { d.errorf("float32 overflow: %v", fv) } urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*float32)(urv.ptr) = float32(fv) } func (d *Decoder) kFloat64(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*float64)(urv.ptr) = d.d.DecodeFloat64() } func (d *Decoder) kInt(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*int)(urv.ptr) = int(chkOvf.IntV(d.d.DecodeInt64(), intBitsize)) } func (d *Decoder) kInt8(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*int8)(urv.ptr) = int8(chkOvf.IntV(d.d.DecodeInt64(), 8)) } func (d *Decoder) kInt16(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*int16)(urv.ptr) = int16(chkOvf.IntV(d.d.DecodeInt64(), 16)) } func (d *Decoder) kInt32(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*int32)(urv.ptr) = int32(chkOvf.IntV(d.d.DecodeInt64(), 32)) } func (d *Decoder) kInt64(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*int64)(urv.ptr) = d.d.DecodeInt64() } func (d *Decoder) kUint(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*uint)(urv.ptr) = uint(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) } func (d *Decoder) kUintptr(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*uintptr)(urv.ptr) = uintptr(chkOvf.UintV(d.d.DecodeUint64(), uintBitsize)) } func (d *Decoder) kUint8(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*uint8)(urv.ptr) = uint8(chkOvf.UintV(d.d.DecodeUint64(), 8)) } func (d *Decoder) kUint16(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*uint16)(urv.ptr) = uint16(chkOvf.UintV(d.d.DecodeUint64(), 16)) } func (d *Decoder) kUint32(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*uint32)(urv.ptr) = uint32(chkOvf.UintV(d.d.DecodeUint64(), 32)) } func (d *Decoder) kUint64(f *codecFnInfo, rv reflect.Value) { urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) *(*uint64)(urv.ptr) = d.d.DecodeUint64() } // ------------ func (e *Encoder) kBool(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeBool(*(*bool)(v.ptr)) } func (e *Encoder) kTime(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeTime(*(*time.Time)(v.ptr)) } func (e *Encoder) kString(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeString(cUTF8, *(*string)(v.ptr)) } func (e *Encoder) kFloat64(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeFloat64(*(*float64)(v.ptr)) } func (e *Encoder) kFloat32(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeFloat32(*(*float32)(v.ptr)) } func (e *Encoder) kInt(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeInt(int64(*(*int)(v.ptr))) } func (e *Encoder) kInt8(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeInt(int64(*(*int8)(v.ptr))) } func (e *Encoder) kInt16(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeInt(int64(*(*int16)(v.ptr))) } func (e *Encoder) kInt32(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeInt(int64(*(*int32)(v.ptr))) } func (e *Encoder) kInt64(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeInt(int64(*(*int64)(v.ptr))) } func (e *Encoder) kUint(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeUint(uint64(*(*uint)(v.ptr))) } func (e *Encoder) kUint8(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeUint(uint64(*(*uint8)(v.ptr))) } func (e *Encoder) kUint16(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeUint(uint64(*(*uint16)(v.ptr))) } func (e *Encoder) kUint32(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeUint(uint64(*(*uint32)(v.ptr))) } func (e *Encoder) kUint64(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeUint(uint64(*(*uint64)(v.ptr))) } func (e *Encoder) kUintptr(f *codecFnInfo, rv reflect.Value) { v := (*unsafeReflectValue)(unsafe.Pointer(&rv)) e.e.EncodeUint(uint64(*(*uintptr)(v.ptr))) } // ------------ // func (d *Decoder) raw(f *codecFnInfo, rv reflect.Value) { // urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) // // if urv.flag&unsafeFlagIndir != 0 { // // urv.ptr = *(*unsafe.Pointer)(urv.ptr) // // } // *(*[]byte)(urv.ptr) = d.rawBytes() // } // func rv0t(rt reflect.Type) reflect.Value { // ut := (*unsafeIntf)(unsafe.Pointer(&rt)) // // we need to determine whether ifaceIndir, and then whether to just pass 0 as the ptr // uv := unsafeReflectValue{ut.word, &zeroRTv, flag(rt.Kind())} // return *(*reflect.Value)(unsafe.Pointer(&uv}) // } // func rv2i(rv reflect.Value) interface{} { // urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) // // true references (map, func, chan, ptr - NOT slice) may be double-referenced as flagIndir // var ptr unsafe.Pointer // // kk := reflect.Kind(urv.flag & (1<<5 - 1)) // // if (kk == reflect.Map || kk == reflect.Ptr || kk == reflect.Chan || kk == reflect.Func) && urv.flag&unsafeFlagIndir != 0 { // if refBitset.isset(byte(urv.flag&(1<<5-1))) && urv.flag&unsafeFlagIndir != 0 { // ptr = *(*unsafe.Pointer)(urv.ptr) // } else { // ptr = urv.ptr // } // return *(*interface{})(unsafe.Pointer(&unsafeIntf{typ: urv.typ, word: ptr})) // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ})) // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ})) // } // func definitelyNil(v interface{}) bool { // var ui *unsafeIntf = (*unsafeIntf)(unsafe.Pointer(&v)) // if ui.word == nil { // return true // } // var tk = reflect.TypeOf(v).Kind() // return (tk == reflect.Interface || tk == reflect.Slice) && *(*unsafe.Pointer)(ui.word) == nil // fmt.Printf(">>>> definitely nil: isnil: %v, TYPE: \t%T, word: %v, *word: %v, type: %v, nil: %v\n", // v == nil, v, word, *((*unsafe.Pointer)(word)), ui.typ, nil) // } // func keepAlive4BytesView(v string) { // runtime.KeepAlive(v) // } // func keepAlive4StringView(v []byte) { // runtime.KeepAlive(v) // } // func rt2id(rt reflect.Type) uintptr { // return uintptr(((*unsafeIntf)(unsafe.Pointer(&rt))).word) // // var i interface{} = rt // // // ui := (*unsafeIntf)(unsafe.Pointer(&i)) // // return ((*unsafeIntf)(unsafe.Pointer(&i))).word // } // func rv2i(rv reflect.Value) interface{} { // urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) // // non-reference type: already indir // // reference type: depend on flagIndir property ('cos maybe was double-referenced) // // const (unsafeRvFlagKindMask = 1<<5 - 1 , unsafeRvFlagIndir = 1 << 7 ) // // rvk := reflect.Kind(urv.flag & (1<<5 - 1)) // // if (rvk == reflect.Chan || // // rvk == reflect.Func || // // rvk == reflect.Interface || // // rvk == reflect.Map || // // rvk == reflect.Ptr || // // rvk == reflect.UnsafePointer) && urv.flag&(1<<8) != 0 { // // fmt.Printf(">>>>> ---- double indirect reference: %v, %v\n", rvk, rv.Type()) // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ})) // // } // if urv.flag&(1<<5-1) == uintptr(reflect.Map) && urv.flag&(1<<7) != 0 { // // fmt.Printf(">>>>> ---- double indirect reference: %v, %v\n", rvk, rv.Type()) // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ})) // } // // fmt.Printf(">>>>> ++++ direct reference: %v, %v\n", rvk, rv.Type()) // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ})) // } // const ( // unsafeRvFlagKindMask = 1<<5 - 1 // unsafeRvKindDirectIface = 1 << 5 // unsafeRvFlagIndir = 1 << 7 // unsafeRvFlagAddr = 1 << 8 // unsafeRvFlagMethod = 1 << 9 // _USE_RV_INTERFACE bool = false // _UNSAFE_RV_DEBUG = true // ) // type unsafeRtype struct { // _ [2]uintptr // _ uint32 // _ uint8 // _ uint8 // _ uint8 // kind uint8 // _ [2]uintptr // _ int32 // } // func _rv2i(rv reflect.Value) interface{} { // // Note: From use, // // - it's never an interface // // - the only calls here are for ifaceIndir types. // // (though that conditional is wrong) // // To know for sure, we need the value of t.kind (which is not exposed). // // // // Need to validate the path: type is indirect ==> only value is indirect ==> default (value is direct) // // - Type indirect, Value indirect: ==> numbers, boolean, slice, struct, array, string // // - Type Direct, Value indirect: ==> map??? // // - Type Direct, Value direct: ==> pointers, unsafe.Pointer, func, chan, map // // // // TRANSLATES TO: // // if typeIndirect { } else if valueIndirect { } else { } // // // // Since we don't deal with funcs, then "flagNethod" is unset, and can be ignored. // if _USE_RV_INTERFACE { // return rv.Interface() // } // urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) // // if urv.flag&unsafeRvFlagMethod != 0 || urv.flag&unsafeRvFlagKindMask == uintptr(reflect.Interface) { // // println("***** IS flag method or interface: delegating to rv.Interface()") // // return rv.Interface() // // } // // if urv.flag&unsafeRvFlagKindMask == uintptr(reflect.Interface) { // // println("***** IS Interface: delegate to rv.Interface") // // return rv.Interface() // // } // // if urv.flag&unsafeRvFlagKindMask&unsafeRvKindDirectIface == 0 { // // if urv.flag&unsafeRvFlagAddr == 0 { // // println("***** IS ifaceIndir typ") // // // ui := unsafeIntf{word: urv.ptr, typ: urv.typ} // // // return *(*interface{})(unsafe.Pointer(&ui)) // // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ})) // // } // // } else if urv.flag&unsafeRvFlagIndir != 0 { // // println("***** IS flagindir") // // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ})) // // } else { // // println("***** NOT flagindir") // // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ})) // // } // // println("***** default: delegate to rv.Interface") // urt := (*unsafeRtype)(unsafe.Pointer(urv.typ)) // if _UNSAFE_RV_DEBUG { // fmt.Printf(">>>> start: %v: ", rv.Type()) // fmt.Printf("%v - %v\n", *urv, *urt) // } // if urt.kind&unsafeRvKindDirectIface == 0 { // if _UNSAFE_RV_DEBUG { // fmt.Printf("**** +ifaceIndir type: %v\n", rv.Type()) // } // // println("***** IS ifaceIndir typ") // // if true || urv.flag&unsafeRvFlagAddr == 0 { // // // println(" ***** IS NOT addr") // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ})) // // } // } else if urv.flag&unsafeRvFlagIndir != 0 { // if _UNSAFE_RV_DEBUG { // fmt.Printf("**** +flagIndir type: %v\n", rv.Type()) // } // // println("***** IS flagindir") // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: *(*unsafe.Pointer)(urv.ptr), typ: urv.typ})) // } else { // if _UNSAFE_RV_DEBUG { // fmt.Printf("**** -flagIndir type: %v\n", rv.Type()) // } // // println("***** NOT flagindir") // return *(*interface{})(unsafe.Pointer(&unsafeIntf{word: urv.ptr, typ: urv.typ})) // } // // println("***** default: delegating to rv.Interface()") // // return rv.Interface() // } // var staticM0 = make(map[string]uint64) // var staticI0 = (int32)(-5) // func staticRv2iTest() { // i0 := (int32)(-5) // m0 := make(map[string]uint16) // m0["1"] = 1 // for _, i := range []interface{}{ // (int)(7), // (uint)(8), // (int16)(-9), // (uint16)(19), // (uintptr)(77), // (bool)(true), // float32(-32.7), // float64(64.9), // complex(float32(19), 5), // complex(float64(-32), 7), // [4]uint64{1, 2, 3, 4}, // (chan<- int)(nil), // chan, // rv2i, // func // io.Writer(ioutil.Discard), // make(map[string]uint), // (map[string]uint)(nil), // staticM0, // m0, // &m0, // i0, // &i0, // &staticI0, // &staticM0, // []uint32{6, 7, 8}, // "abc", // Raw{}, // RawExt{}, // &Raw{}, // &RawExt{}, // unsafe.Pointer(&i0), // } { // i2 := rv2i(reflect.ValueOf(i)) // eq := reflect.DeepEqual(i, i2) // fmt.Printf(">>>> %v == %v? %v\n", i, i2, eq) // } // // os.Exit(0) // } // func init() { // staticRv2iTest() // } // func rv2i(rv reflect.Value) interface{} { // if _USE_RV_INTERFACE || rv.Kind() == reflect.Interface || rv.CanAddr() { // return rv.Interface() // } // // var i interface{} // // ui := (*unsafeIntf)(unsafe.Pointer(&i)) // var ui unsafeIntf // urv := (*unsafeReflectValue)(unsafe.Pointer(&rv)) // // fmt.Printf("urv: flag: %b, typ: %b, ptr: %b\n", urv.flag, uintptr(urv.typ), uintptr(urv.ptr)) // if (urv.flag&unsafeRvFlagKindMask)&unsafeRvKindDirectIface == 0 { // if urv.flag&unsafeRvFlagAddr != 0 { // println("***** indirect and addressable! Needs typed move - delegate to rv.Interface()") // return rv.Interface() // } // println("****** indirect type/kind") // ui.word = urv.ptr // } else if urv.flag&unsafeRvFlagIndir != 0 { // println("****** unsafe rv flag indir") // ui.word = *(*unsafe.Pointer)(urv.ptr) // } else { // println("****** default: assign prt to word directly") // ui.word = urv.ptr // } // // ui.word = urv.ptr // ui.typ = urv.typ // // fmt.Printf("(pointers) ui.typ: %p, word: %p\n", ui.typ, ui.word) // // fmt.Printf("(binary) ui.typ: %b, word: %b\n", uintptr(ui.typ), uintptr(ui.word)) // return *(*interface{})(unsafe.Pointer(&ui)) // // return i // }