github.com/qioalice/ekago/v3@v3.3.2-0.20221202205325-5c262d586ee4/internal/ekaclike/pointer.go (about) 1 // Copyright © 2020. All rights reserved. 2 // Author: Ilya Stroy. 3 // Contacts: iyuryevich@pm.me, https://github.com/qioalice 4 // License: https://opensource.org/licenses/MIT 5 6 package ekaclike 7 8 import ( 9 "unsafe" 10 ) 11 12 /* 13 TakeRealAddr takes and returns a real address of the variable you passed. 14 It returns nil if nil is passed. 15 16 var i int 17 _ = &i == TakeRealAddr(i) // true 18 19 This function exist to extend standard Golang & operator. 20 Using this function you can take an address of some things, 21 that "cannot be addressed" in Golang policy. Like functions, for example. 22 23 What you CAN do with functions and their addresses: 24 25 f := func(){} 26 _ = &f // 0x... 27 28 What you CANNOT do with functions and their addresses: 29 30 func foo() {} 31 func bar() { _ = &foo } // compilation err 32 33 What you CAN do now using TakeRealAddr() with functions and their addresses: 34 35 func foo() {} 36 type T struct{} 37 func (_ T) bar() {} 38 39 func main() { 40 var t T 41 ptr1 := TakeRealAddr(foo) // 0x... 42 ptr2 := TakeRealAddr((*T).bar) // 0x... 43 ptr3 := TakeRealAddr(t.bar) // 0x... 44 } 45 46 Speaking about functions, if you want to convert it back, 47 and be able to call a function address of which you got using TakeRealAddr(), 48 you need to pass it through Addr2Callable() or just use TakeCallableAddr(). 49 */ 50 func TakeRealAddr(i any) unsafe.Pointer { 51 return UnpackInterface(i).Word 52 } 53 54 /* 55 TakeCallableAddr extends TakeRealAddr functionality, 56 providing to you a mechanism to get a real address of any function, which you may: 57 58 - Compare with another, obtained the same way, address; 59 - Doing other unsafe but interest stuff with function address in C-style; 60 - Convert that address back and call the function. 61 62 It returns nil if nil is passed. 63 64 Tip: 65 Using this function you may not only compare addresses of function, 66 convert addresses to functions, vice-versa and call them, but 67 you can also avoid type checks while any conversion. Yes, C-style, just as we like. 68 69 Usage: 70 71 type F = func(f float64) (int32, int32) 72 func foo(x1, x2 int32) (int32, int32) { return x1, x2 } 73 untypedPtr := TakeCallableAddr(foo) 74 x1, x2 := (*(*F)(untypedPtr))(math.PI) 75 76 Now, x1 and x2 contains first and last 32 bytes of math.PI constant as Golang int32. 77 It's a synthetic example. Real world examples will be presented later. 78 79 ----- 80 81 WARNING! 82 DO NOT PASS SOMETHING BUT EITHER FUNCTIONS, FUNCTORS, CLOSURES, LAMBDAS, ETC. 83 YOU MUST PASS ONLY THAT THING THAT MAY BE CALLED. 84 UNDEFINED BEHAVIOUR OTHERWISE! 85 86 WARNING! 87 DESPITE THE FACT, IT IS POSSIBLE TO CONVERT ADDRESS BACK AND CALL THE FUNCTION, 88 THERE MIGHT BE SOME PROBLEMS WHEN YOU'RE TRYING TO WORK AROUND METHODS, 89 NOT JUST FUNCTIONS. 90 DO IT ON YOUR OWN RISK. 91 92 WARNING! 93 USING THIS FUNCTION IS VERY, VERY DANGEROUS. 94 YOU MAY GET UNDEFINED BEHAVIOUR, PANIC 95 AND IT IS SO DEPENDED OF THE GOLANG INTERNAL IMPLEMENTATIONS. 96 THIS FUNCTION NEVER USED IN OTHER PARTS OF THAT LIBRARY. 97 98 BE CAREFULLY! 99 */ 100 func TakeCallableAddr(fn any) unsafe.Pointer { 101 102 // There is no need nil checks, 103 // because TakeRealAddr and AddrConvert2Callable already has it 104 return Addr2Callable(TakeRealAddr(fn)) 105 } 106 107 /* 108 Addr2Callable transforms an address of some function obtained by TakeRealAddr() 109 to that kind of address, you can cast to the typed pointer to the some function, 110 dereference it and call. 111 112 See TakeRealAddr(), TakeCallableAddr() for more info. 113 */ 114 func Addr2Callable(realPtr unsafe.Pointer) (callablePtr unsafe.Pointer) { 115 116 type fptr struct { 117 ptr unsafe.Pointer 118 } 119 120 if realPtr == nil { 121 return nil 122 } 123 124 o := new(fptr) 125 o.ptr = realPtr 126 127 return unsafe.Pointer(&o.ptr) 128 } 129 130 /* 131 Addr2Real transforms a callable address of some function, 132 obtained by TakeCallableAddr() 133 to a simple, real, non-callable address of that function. 134 */ 135 func Addr2Real(callablePtr unsafe.Pointer) (realPtr unsafe.Pointer) { 136 137 if callablePtr == nil { 138 return nil 139 } 140 141 return *(*unsafe.Pointer)(callablePtr) 142 }