Need a way to get a mutable char* argument in a callback function
Closed this issue · 2 comments
I am wondering how I get a C header that looks like this:
typedef struct callbacks {
size_t (*display)(void const *, char *, size_t);
} callbacks_t;
as opposed to this:
typedef struct callbacks {
size_t (*display)(void const *, int8_t *, size_t);
} callbacks_t;
Here is the Rust code:
#[ffi_export]
#[derive_ReprC]
#[repr(C)]
pub struct callbacks {
display: extern "C" fn(*const c_void, *mut c_char, usize) -> usize,
}
Unfortunately
#[ffi_export]
#[derive_ReprC]
#[repr(C)]
pub struct callbacks {
display: extern "C" fn(*const c_void, safer_ffi::char_p::char_p_raw, usize) -> usize,
}
produces a const
buffer pointer
typedef struct callbacks {
size_t (*display)(void const *, char const *, size_t);
} callbacks_t;
I am not sure if the better solution is to have a safer_ffi::char_p::char_p_raw_mut type, or if the best solution is to have a special case in the header generation code so that c_char
gets mapped to char, rather than being reduced to its fundamental Rust type (i8). Or if I just missed some existing mechanism already in place to handle this.
I'm happy to do the implementation and whatever testing is required, but I want to know what you feel is the best solution.
Thank you.
This is related to this thread: https://users.rust-lang.org/t/safer-ffi-question-how-to-make-c-char-into-char-rather-than-int8-t/92929 although there isn't any substantial information in the thread that isn't also here.
Your update on the forum raised several important points. Agreed that relying on the C side to provide properly formatted UTF-8 is probably not a great idea. However, most C programmers can manage null-termination, and we kinda have to trust them not to overwrite the end of buffers. (often misplaced trust, but that's fundamental to C). So &mut [AsciiByte]
is exactly what I'm hoping for.
char_p::Malloc
sounds very useful, but orthogonal to the reasons I filed this issue. In my case, the buffer itself will be both allocated and dropped on the Rust side, so the allocator isn't my current hangup.
I'm looking for something a lot more like char_p::Ref
(except mut) or char_p::Box
(without ownership transfer), or perhaps even making the safer_ffi::c_char
type public so I can expose a slice of them.
My use case follows a pattern like this:
pub struct Callbacks {
display: extern "C" fn(*const c_void, *mut c_char, usize) -> usize,
}
struct MyType {
callbacks: &'static Callbacks,
payload: *mut c_void,
}
impl fmt::Display for MyType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut buffer = [0u8; 512];
let bytes_written = (self.callbacks.display)(self.payload, buffer.as_mut_ptr().cast(), 512);
let text = std::str::from_utf8(&buffer[0..bytes_written]).expect("Invalid UTF-8");
write!(f, "{}", text)
}
}
Thank you for all your help and for writing safer_ffi itself. If there is anything I can do to help with the implementation or testing please let me know.
Thanks again.
For the sake of speed, I've gone with exposing the c_char
type, since it's a sensible thing to do anyways, and now you ought to be able to use *mut ::safer_ffi::c_char
or c_slice::Mut<'_, ::safer_ffi::c_char>
for your use case.
I'll still think about having a char_p::Mut<'_>
variant would DerefMut
to AsciiByte
or something, it may just take more time to feature it