Hello I want to know how do I port from C to Rust?

See like this old thread

I really don't understand how do I port function pointer like

Example:

int
wl_proxy_add_listener(struct wl_proxy *proxy, void (**implementation)(void), void *data);

But how do I translate to Rust like this?
void (**implementation)(void) Warning it has double pointers inside function pointer.
To implementation: *mut unsafe extern "C" fn() or
implementation: Option<*mut unsafe extern "C" fn()>

Is it correct or wrongly??

The only time you should ever use Option for FFI is when you are using it to wrap a non-null pointer — more precisely, one of the types listed in the representation documentation of Option for which the representation is guaranteed. *mut T is a nullable pointer, so Option<*mut T> is not ever suitable for FFI.

implementation: *mut unsafe extern "C" fn() is appropriate for this case.

(An example of where Option would be appropriate is if you wanted to pass a single function pointer or null: then Option<unsafe extern "C" fn()> would be an appropriate type, because Rust fn types are non-null pointers.)

implementation: *mut unsafe extern "C" fn() is the equivalent to the C code. however, you may be able to use better alternatives depending on the scenario.

for example, these all have the same representation and are abi compatible with the strict translation of raw pointer, any of these might be a more descriptive alternative, but the correctness cannot be determined by simply looking at the C function prototype alone, you must consult the api documentation:

// for brevity, I'll use this shorthand for the function pointer type:
type FP = unsafe extern "C" fn();

//----------------------
// cases of input argument, although the extra level of indirection in this case feels "unnatural"
//
// for input arguments, I don't think nested `Option`s really make sense
// so I don't consider them here
//----------------------
// case 1: scoped input argument
implementation: &FP,
// case 1.5: nullable, or, optional:
implementation: Option<&FP>,
// case 2: input argument with transferred ownerhsip
//   this is abi compatible, but prefer wrappers using `Box::into_raw()`
implementation: Box<FP>,
// case 2.5, nullable
implementation: Option<Box<FP>>,

//----------------------
// the argument is output or inout, which is more likely
//----------------------
// case 3: can never be null:
implementation: &mut FP,
// case 4: the output location is optional:
implementation: Option<&mut FP>,
// case 5: the received result might be null:
implementation: &mut Option<FP>,
// case 6: the output location is optional, and the result might also be null:
implementation: Option<&mut Option<FP>>,

p.s.

when you say "port" C code with said function pointer, I have two interpretations:

  • the C code you want to port is client code of the api wl_proxy_add_listener()

  • you want to port the implmentation of the api, or in other words, you want to rewrite the api in rust

if it's the second case, more advanced (still abi compatible, of course) rust types may also be chosen, for example, &mut MaybeUninit to indicate an output argument.

Thanks! But I have ported from original latest version of library wayland into rust.

Warning if you don't expect that:
example:

void (**implementation)(void)

Means in Rust:

implementation: mut unsafe extern "C" fn()

Example other way like this:

typedef in (*pfn_printf)(const char*, ...)

in Rust:

pfn_printf: unsafe fn(*const i8, ...) -> i32;

I expect that

But I have problem with dispatcher and roundtrip :confused: I will try to fix soon. Thanks! I am working on my own kernel + relibc-liked runtime for next successor of Linux.