I’m trying to write a macro that takes a function, creates a wrapper for it, passes the wrapper to @cfunction and finally passes the function pointer to an external C library.
To further clarify the use-case here: I want to create a type-stable wrapper of the function and pass this to the C-Library. The wrapper should extract the arguments from a C pointer and then call the function, all without runtime dispatch.
I tried several things, that dont work, see below.
My question:
How can this could be done? Is this even possible?
Approach 1: Defining wrapper and passing to @cfunction.
macro _test_macro_func_wrapped_1(func)
func_esc = esc(func) # must be escaped, because macro lives in package
quote
wrapped = function ()
println("Execute Wrapper")
r = $func_esc()
return println("Execute Wrapper result: ", r)
end
wrapped() # works
# ERROR HERE - "wrapped" not defined
ptr = @cfunction(wrapped, Cvoid, ())
@info "Function ptr:" ptr
ptr
end
end
Approach 2:
Try to avoid macro hygiene (but not working)
macro _test_macro_func_wrapped_2(func)
func_esc = esc(func) # escape the function
wrapper_name = :wrapper
println("Wrapper name: ", wrapper_name)
quote
# Try to avoid auto generated name, but somehow its still generated
function ($wrapper_name)()
println("Execute Wrapper")
r = $func_esc(10)
return println("Execute Wrapper result: ", r)
end
($wrapper_name)() # works
$wrapper_name # works
@info "Method:" $wrapper_name # Works
# ERROR HERE: "wrapper" not defined in Main (but also not in the package)
ptr = @cfunction($wrapper_name, Cvoid, ())
@info "Function ptr:" ptr
ptr
end
end
Approach 3:
Avoid macro hygiene and force definition of the wrapper via eval. But fails, because of an “syntax error” if esc() is used, or if esc() is not used, then the outer function cannot be referenced.
macro _test_macro_func_wrapped_3(func)
func_esc = esc(func) # escape the function
wrapper_name = :wrapper
package_name = @__MODULE__
package_wrapper_expr = Expr(:., package_name, :(:wrapper))
println("Wrapper name: ", wrapper_name)
println("Package wrapper expr: ", package_wrapper_expr)
wrapper_def = quote
function ($wrapper_name)()
println("Execute Wrapper")
r = $(func)(10)
return println("Execute Wrapper result: ", r)
end
end
# ERROR here: LoadError: syntax: invalid syntax (escape (outerref my_scalar_function))
# or if esc() is ommited: UndefVarError: `my_scalar_function` not defined in `package`
eval(wrapper_def)
quote
($package_wrapper_expr)()
$package_wrapper_expr
@info "Method:" $package_wrapper_expr
ptr = @cfunction($package_wrapper_expr, Cvoid, ())
@info "Function ptr:" ptr
ptr
end
end