Created
April 28, 2018 20:08
-
-
Save rbranson/1d0bc8ccae75afd91fc633381084b149 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package stupid | |
import ( | |
"fmt" | |
"reflect" | |
"unsafe" | |
) | |
type iptr struct { | |
itab uintptr | |
ptr uintptr | |
} | |
func (p iptr) String() string { | |
return fmt.Sprintf("itab=0x%x, ptr=0x%x", p.itab, p.ptr) | |
} | |
func (p iptr) Interface() interface{} { | |
return *(*interface{})(unsafe.Pointer(&p)) | |
} | |
type interfaceFactory struct { | |
ptritab unsafe.Pointer | |
} | |
func newInterfaceFactory(t reflect.Type) interfaceFactory { | |
// Need something valid to point at, just a throwaway | |
tmp := struct{}{} | |
ptr := unsafe.Pointer(&tmp) | |
// Construct a pointer of type *t that points at tmp | |
ptrPtrVal := reflect.NewAt(t, ptr) | |
// Build interface{*t, ptrPtrVal=>tmp} | |
ptrPtrIface := ptrPtrVal.Interface() | |
// Coerce the above interface{} into a touchable struct | |
ptrPtrIptr := *(*iptr)(unsafe.Pointer(&ptrPtrIface)) | |
// All we care about is the itab field, which contains the | |
// type information to copy onto factory-created interface{}s | |
itabPtr := unsafe.Pointer(ptrPtrIptr.itab) | |
return interfaceFactory{ | |
ptritab: itabPtr, | |
} | |
} | |
// takes interface{Struct, ptr=>struct}, returns interface{*FieldType, ptr=>&struct.field} | |
func (f *interfaceFactory) PtrToStructField(any interface{}, field reflect.StructField) interface{} { | |
// creates an iptr struct out of the 'any' interface | |
anyIptr := *(*iptr)(unsafe.Pointer(&any)) | |
// construct the new pointer (&struct.field) that will be returned | |
interptr := unsafe.Pointer(anyIptr.ptr + field.Offset) | |
// construct the interface{} with cached type information, pointing at &struct.field | |
newIptr := iptr{ | |
itab: uintptr(f.ptritab), | |
ptr: uintptr(interptr), | |
} | |
return newIptr.Interface() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment