I am looking for a way to ensure a struct outlives the parameter given to a method of that struct. Even if the struct doesn't hold a reference to that data after leaving the method.
This is for wrapped raw pointers fed to an FFI. I want to guarantee that the struct implementing the FFI outlives the Option<&'a Any>
I use to feed the Rust object to the pointer wrapper.
Context
is the FFI wrapper.
Data
holds different types that map to FFI types. The FFI functions copies all these types immediately before returning.
Except raw pointers.
So I add a lifetime specifier to Context
just for those and use that in send_data()
.
But somehow this is not enough. I expected below code to not compile.
Edit: someone one the Rust Discord suggested making &self
mut
able in send_data()
. This has the desired effect but my FFI is thread safe (and stateless) and send_data()
is time critical. So I would very much like to avoid this.
use std::any::Any;
use std::marker::PhantomData;
struct IntegerArray<'a> {
data: &'a [i32],
}
struct WrappedRawPointer<'a> {
ptr: *const std::ffi::c_void,
_marker: PhantomData<&'a ()>,
}
impl<'a> WrappedRawPointer<'a> {
fn new(data: Option<&'a dyn Any>) -> Self {
Self {
ptr: data
.map(|p| p as *const _ as *const std::ffi::c_void)
.unwrap_or(std::ptr::null()),
_marker: PhantomData,
}
}
}
enum Data<'a, 'b> {
IntegerArray(IntegerArray<'a>),
WrappedRawPointer(WrappedRawPointer<'b>),
}
struct Context<'a> {
ctx: u32,
_marker: PhantomData<&'a ()>,
}
impl<'a> Context<'a> {
fn new() -> Self {
Self {
ctx: 0, // Call FFI to initialize context
_marker: PhantomData,
}
}
fn send_data(&self, data: Data<'_, 'a>) {
match data {
Data::IntegerArray(_i) => (), // Call FFI function
Data::WrappedRawPointer(_p) => (), // Call FFI function
}
}
}
fn main() {
let ctx = Context::new();
{
let some_float: f32 = 42.0;
ctx.send_data(
Data::WrappedRawPointer(
WrappedRawPointer::new(
Some(&some_float)
)
)
);
// I would like rustc to complain
// here that some_float does not
// outlive ctx
}
// Explicitly drop outside
// the previous block to
// prevent rustc from being
// clever
drop(ctx);
}