It's hard to provide a sample when you don't specify which end is supposed to call which and how.
For starters,
#[repr(C)]
struct F {
data: [*const c_char; 3],
}
is the Rust equivalent of:
typedef struct {
char const * data[3];
} F;
So, if C happened to have a pointer to an F
(a F *
) as a parameter, so as to fill the pointee F
with the values of d
, you'd simply write, in C:
void init_F (
F * out_f)
{
// static
char const * d[3] = { "11qweqweqwesdfsdf", "hhdfgkshdfjhaskdfh", "ksdhf" };
for (size_t i = 0; i < 3; ++i) {
out_f->data[i] = d[i];
}
}
so as to, from Rust:
extern "C" {
fn init_F (out_f: *mut F);
}
let mut f: F = F {
data: [ptr::null_mut(); 3],
};
unsafe {
init_f(&mut f);
}
// Now you got the three `char const *` pointers inside `f.data`;
// time to get actual string-like stuff:
// Only valid as long as the given FFI / C strings remain valid;
// the lifetime `'c` represents that; although because of the FFI,
// Rust has no idea what the real value of `'c` is, and so this as
// dangerous as the `*const char` just above!
struct GRef<'c> {
data: [&'c CStr; 3],
}
let g_ref = GRef {
data: unsafe {
[
CStr::from_ptr(f.data[0]),
CStr::from_ptr(f.data[1]),
CStr::from_ptr(f.data[2]),
]
},
};
/// Owned / `strdup`-ed version of `GRef`:
#[derive(Debug)]
struct G {
data: [CString; 3],
}
let g = G {
data: [
g_ref.data[0].to_owned(), // `strdup`,
g_ref.data[1].to_owned(), // `strdup`,
g_ref.data[2].to_owned(), // `strdup`,
],
};
and now, optionally, you'd like to work with UTF-8 encoded strings in Rust (i.e., &str
and String
):
struct H {
data: [String; 3],
}
let h = H {
data: [
mem::take(&mut g.data[0]).into_string()?,
mem::take(&mut g.data[1]).into_string()?,
mem::take(&mut g.data[2]).into_string()?,
]
};
and so on and so forth. Hard to give further code snippets without a more concrete example of what you are trying to achieve