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  }