I've written a function in C with this signature:
write_stuff(char **pages, uint32 page_count);
pages
will be an array of 128 elements, with each element either NULL or pointing to a char array of 8192 bytes. So, an array of arrays with fixed, known sizes.
I need to populate the arrays in Rust and pass them to the C function. When I generate a Rust signature using bindgen, it produces this:
extern "C" {
pub fn write_stuff(pages: *mut *mut ::std::os::raw::c_char, page_count: u32,);
}
Now, how do I declare a variable in Rust that I can populate and pass to this function?
I tried this:
let mut pages = [Option <[u8; 8192]>; 128];
but it doesn't compile.
This does compile:
type MyPage = Option<[u8; 8192]>;
let myarray: [MyPage; 128] = [None; 128];
but I'm not clear on whether it would store the data in the right format, or how to cast it appropriately:
let pages: *mut *mut ::std::os::raw::c_char = myarray.as_mut_ptr() as // what goes here?;
I believe the Rust type you're looking for is &[Option<&[u8; 8192]>]
.
The C version uses a double pointer, so you need to make sure the inner type is a reference . Option<&T>
shows that the reference is nullable and the null pointer optimization guarantees that it has the same size as T
.
I've tested that the code below works as expected, but I'm not 100% sure this type conversion is sound so I'd be careful using this in production code.
Rust main.rs
#[link(name = "mylib")]
extern "C" {
pub fn write_stuff(pages: *mut *mut ::std::os::raw::c_char, page_count: u32);
}
pub fn write_stuff_rust(pages: &[Option<&[u8; 8192]>]) {
unsafe { write_stuff(pages.as_ptr() as *mut _, pages.len() as u32) }
}
fn main() {
let page1: [u8; 8192] = [b'a'; 8192];
let page3: [u8; 8192] = [b'b'; 8192];
let page4: [u8; 8192] = [b'c'; 8192];
let page7: [u8; 8192] = [b'd'; 8192];
let pages: Vec<Option<&[u8; 8192]>> = vec![
Some(&page1),
None,
Some(&page3),
Some(&page4),
None,
None,
Some(&page7),
];
write_stuff_rust(&pages);
}
C mylib.c
#include <stdio.h>
#include <stdint.h>
void write_stuff(char **pages, uint32_t page_count) {
for (uint32_t i = 0; i < page_count; i++) {
printf("%d=%p\n", i, pages[i]);
if (pages[i]) {
for (size_t j = 0; j < 8192; j++) {
putchar(pages[i][j]);
}
putchar('\n');
} else {
puts("<empty>");
}
}
}