I am working on an integration of LV2 atoms for Rust, which are slice-based dynamically sized types (DSTs). In general, atoms are created by the host or other plugins and my code receives only a thin pointer to them. Therefore, I need to create a fat pointer to a slice-based DST from a thin pointer. This is how my code roughly looks like:
#[repr(C)]
struct Atom {
/// The len of the `data` field.
len: u32,
/// The data.
data: [u8],
}
/// This is the host. It creates the atom in a generally unknown way and calls
/// the plugin's run function. This isn't really part of my code, but it is
/// needed to understand it.
fn host() {
// The raw representation of the atom
let raw_representation: [u8; 8] = [
// len: Raw representation of a `u32`. We have four data bytes.
4, 0, 0, 0,
// The actual data:
1, 2, 3, 4
];
let ptr: *const u8 = raw_representation.as_ptr();
plugin_run(ptr);
}
/// This function represents the plugin's run function:
/// It only knows the pointer to the atom, nothing more.
fn plugin_run(ptr: *const u8) {
// The length of the data.
let len: u32 = *unsafe { (ptr as *const u32).as_ref() }.unwrap();
// The "true" representation of the fat pointer.
let fat_pointer: (*const u8, usize) = (ptr, len as usize);
// transmuting the tuple into the actuall raw pointer.
let atom: *const Atom = unsafe { std::mem::transmute(fat_pointer) };
println!("{:?}", &atom.data);
}
The interesting line is the penultimate line in plugin_run
: Here, a fat pointer is created by transmuting a tuple containing the thin pointer and the length. This approach works, but it uses the highly unsafe transmute
method. According to the documentation, this method should be the absolute last resort, but as far as I understand the design of Rust, I'm doing nothing that should be unsafe. I'm just creating a pointer!
I don't want to stick with this solution. Is there a safe way to create pointers to array-based structs apart from using transmute
?
The only thing that goes in this direction is std::slice::from_raw_parts
, but it is also unsafe, directly creates a reference, not a pointer, and works exclusively for slices. I found nothing in the standard library, I found nothing on crates.io, I even found no issues in the git repo. Am I searching for the wrong keywords? Is something like this actually welcome in Rust?
If nothing like this exists, I would go forth and create an issue for that in Rust's Github repo.
EDIT: I shouldn't have said something about LV2, it made the discussion go in a completely different direction. Everything works just fine, I've deeply thought about the data models and tested it; The only thing I would like to have is a safe alternative to using transmute
to create fat pointers. :(
DST
so you will have to precise what your hypothetical C API is doing. I check a little on drobilla.net/docs/lilv doesn't give me much information. YourAtom
structure is not C compatible see stackoverflow.com/a/53050526/1233251. So, If you want to do Rust-to-C, your question don't make sense. – Stargateur&Atom
, assuming you can make guarantees about its lifetime or a*const Atom
if not? – Peter Hall