Rust static function fn pointer, which value to initialize?

Viewed 942

I'm trying to create a Rust library callable from C:

use std::os::raw::{c_int};

type OnDataCallback = unsafe extern "C" fn(data: *mut u8, len: usize) -> c_int;

static mut onDataCallback_: OnDataCallback = std::ptr::null();

#[no_mangle]
pub extern "C" fn registerOnDataCallback(
    data: *const u8, len: usize,
    cb: Option<OnDataCallback>) -> c_int
{
    onDataCallback_ = cb.unwrap();
    return 0;
}

#[no_mangle]
pub extern "C" fn doSomething()
{
    unsafe{onDataCallback_(mut "hello world" , 100)};
}

But I'm getting:

--> interface.rs:5:46
  |
5 | static mut onDataCallback_: OnDataCallback = std::ptr::null();
  |                                              ^^^^^^^^^^^^^^^^ expected fn pointer, found *-ptr
  |
  = note: expected fn pointer `unsafe extern "C" fn(*mut u8, usize) -> i32`
            found raw pointer `*const _`

I don't have idea on what to put there for the initial value. I can't let it without one, and I can't put null. What should I put?

PS: if what I'm doing is a bad practice, please show me a good one. I'm new at Rust.

2 Answers

You should wrap it in an Option and initialize it with None.

static mut onDataCallback_: Option<OnDataCallback> = None;

You can initialize it with a function that panics:

static mut ON_DATA_CALLBACK: OnDataCallback = init;

extern "C" fn init(_: *mut u8, _: usize) -> c_int {
    panic!("Function pointer not initialized");
}

Be aware that static mut is wildly unsafe, and its use is generally discouraged, because it's so difficult use it correctly. A safe alternative is to use a RefCell Mutex in a static. Since Mutex has interior mutability, the static doesn't need to be mutable.

A better solution would be to use once_cell or lazy_static to initialize the function the first time doSomething() is called.

By the way, Rust string literals are always immutable. You can get a mutable string by allocating a String. See this playground.

Related