github.com/inaneverb/ekacore/ekaunsafe/v4@v4.0.0/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 ekaunsafe
     7  
     8  import (
     9  	"unsafe"
    10  )
    11  
    12  // TakeRealAddr takes and returns a real address of the variable you passed.
    13  // It returns nil if nil is passed.
    14  //
    15  //	var i int
    16  //	_ = &i == TakeRealAddr(i) // true
    17  //
    18  // This function exist to extend standard Golang & operator.
    19  // Using this function you can take an address of some things,
    20  // that "cannot be addressed" in Golang policy. Like functions, for example.
    21  //
    22  // What you CAN do with functions and their addresses:
    23  //
    24  //	f := func(){}
    25  //	_ = &f // 0x...
    26  //
    27  // What you CANNOT do with functions and their addresses:
    28  //
    29  //	func foo() {}
    30  //	func bar() { _ = &foo } // compilation err
    31  //
    32  // What you CAN do with functions and their addresses using TakeRealAddr():
    33  //
    34  //	func foo() {}
    35  //	type T struct{}
    36  //	func (_ T) bar() {}
    37  //
    38  //	func main() {
    39  //	        var t T
    40  //	        ptr1 := TakeRealAddr(foo)      // 0x...
    41  //	        ptr2 := TakeRealAddr((*T).bar) // 0x...
    42  //	        ptr3 := TakeRealAddr(t.bar)    // 0x...
    43  //	}
    44  //
    45  // Speaking about functions, if you want to convert it back,
    46  // and be able to call a function address of which you've got by TakeRealAddr(),
    47  // you need to pass it to Addr2Callable() or just use TakeCallableAddr().
    48  func TakeRealAddr(i any) unsafe.Pointer {
    49  	return UnpackInterface(i).Word
    50  }
    51  
    52  // TakeCallableAddr extends TakeRealAddr functionality,
    53  // providing you a mechanism to get a real address of any function,
    54  // using which you may:
    55  //
    56  //   - Compare with another, obtained the same way, address;
    57  //   - Doing other unsafe but interest stuff with function address in C-style;
    58  //   - Convert that address back and call the function.
    59  //
    60  // It returns nil if nil is passed.
    61  //
    62  // Tip:
    63  // Using this function you may not only compare addresses of function,
    64  // convert addresses to functions, vice-versa and call them,
    65  // but you can also avoid type checks while any conversion.
    66  // Yes, C-style, just as we like.
    67  //
    68  // Usage:
    69  //
    70  //	type F = func(f float64) (int32, int32)
    71  //	func foo(x1, x2 int32) (int32, int32) { return x1, x2 }
    72  //	untypedPtr := TakeCallableAddr(foo)
    73  //	x1, x2 := (*(*F)(untypedPtr))(math.PI)
    74  //
    75  // Now, x1 and x2 contains first and last 32 bytes of math.PI constant
    76  // 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, 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. DO IT ON YOUR OWN RISK.
    90  //
    91  // WARNING!
    92  // USING THIS FUNCTION (AND MECHANISM) IS VERY, VERY DANGEROUS.
    93  // YOU MAY GET UNDEFINED BEHAVIOUR, PANIC, UNIVERSE COLLAPSE, ETC.
    94  // AND IT DEPENDS ON THE GOLANG INTERNAL IMPLEMENTATIONS.
    95  //
    96  //	THIS FUNCTION NEVER USED IN OTHER PARTS OF THAT LIBRARY.
    97  //	THIS FUNCTION NEVER USED IN OTHER PARTS OF THAT LIBRARY.
    98  //	THIS FUNCTION NEVER USED IN OTHER PARTS OF THAT LIBRARY.
    99  //	THIS FUNCTION NEVER USED IN OTHER PARTS OF THAT LIBRARY.
   100  //
   101  // BE CAREFULLY!
   102  func TakeCallableAddr(fn any) unsafe.Pointer {
   103  
   104  	// There is no need nil checks,
   105  	// because TakeRealAddr and AddrConvert2Callable already has it
   106  	return Addr2Callable(TakeRealAddr(fn))
   107  }
   108  
   109  // Addr2Callable transforms an address of some function to that kind of address,
   110  // you can cast to the typed pointer of some function, dereference it and call.
   111  //
   112  // See TakeRealAddr(), TakeCallableAddr() for more info.
   113  func Addr2Callable(realPtr unsafe.Pointer) (callablePtr unsafe.Pointer) {
   114  
   115  	type FuncPointer struct {
   116  		ptr unsafe.Pointer
   117  	}
   118  
   119  	if realPtr == nil {
   120  		return nil
   121  	}
   122  
   123  	var o = new(FuncPointer)
   124  	o.ptr = realPtr
   125  
   126  	return unsafe.Pointer(&o.ptr)
   127  }
   128  
   129  // Addr2Real transforms a callable address of some function,
   130  // obtained by TakeCallableAddr() to a simple, real,
   131  // non-callable address of that function.
   132  func Addr2Real(callablePtr unsafe.Pointer) (realPtr unsafe.Pointer) {
   133  
   134  	if callablePtr == nil {
   135  		return nil
   136  	}
   137  
   138  	return *(*unsafe.Pointer)(callablePtr)
   139  }