I have a FFI signature I need to implement:
pub unsafe extern fn f(header_size: u32, header_ptr: *mut u8) -> i32;
A FFI caller is expected to provide a buffer header_ptr
and the size of that buffer header_size
. Rust is expected to fill a string into that buffer up to header_size
, and return 0
if successful. The FFI caller is expected to interpret the string as ASCII.
How can I fill that buffer the most idiomatic way, given I have a headers: &str
with the content I want to provide?
Right now I have:
let header_bytes = slice::from_raw_parts_mut(header_ptr, header_size as usize);
if header_bytes.len() < headers.len() { return Errors::IndexOutOfBounds as i32; }
for (i, byte) in headers.as_bytes().iter().enumerate() {
header_bytes[i] = *byte;
}
But that feels wrong.
Edit, I think this is not an exact duplicate to this because my question relates to strings, and IIRC there were special considerations when converting &str to CStrings.
Since C strings are not much more than 0-terminated byte arrays converting from Rust strings is very straight forward. Almost every valid Rust string is also a valid C string, but you have to make sure that the C string ends with a 0-character and that there are no 0-characters anywhere else in the string.
Rust provides a type that takes care of the conversion: CString
.
If your input string was successfully converted to a CString
you can simply copy the bytes without worrying about the details.
use std::slice;
use std::ffi::CString;
pub unsafe extern fn f(header_size: u32, header_ptr: *mut u8) -> i32 {
let headers = "abc";
let c_headers = match CString::new(headers) {
Ok(cs) => cs,
Err(_) => return -1, // failed to convert to C string
};
let bytes = c_headers.as_bytes_with_nul();
let header_bytes = slice::from_raw_parts_mut(header_ptr, header_size as usize);
header_bytes[..bytes.len()].copy_from_slice(bytes);
0 // success
}
fn main() {
let mut h = [1u8; 8];
unsafe {
f(h.len() as u32, h.as_mut_ptr());
}
println!("{:?}", h); // [97, 98, 99, 0, 1, 1, 1, 1]
}
Note that I left out the length check for brevity. header_bytes[..bytes.len()]
will panic if the buffer is too short. This is something you will want to avoid if f
is called from C.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With