I've recently written a bunch of unsafe code and am now fighting with an invariant which I don't know how to deal with. I stripped the example bellow down as much as possible, but it's still quite a lot of code, sorry. In the real solution, I make sure that the scarry generic parameter in get_second_as
just affects *const Fn() of a list which have the correct signature. Link to the full project is here.
Does anybody know how to restrict all inner references of T to the lifetime of &'a self intead of 'static in get_second_as? As lifetimes are defined by the caller, I guess that this must somehow be embedded in RefFamily?
I know that I could just use Wrapper<Rc> and everything works fine. But I'd prefer a solution, where references could be used, as i make sure, that all references in these constructor-Lambdas have a shorter or same lifetime as Container.
use core::{any::Any, marker::PhantomData};
#[test]
fn lifetime_demo() {
let c = Container::new(3);
let w = c.get_second_as::<Query<Wrapper>>();
// Shouldn't compile anymore when drop is uncommented.
// Unfortunately it does, because Wrapper.0 is &'static (results in undefined behaviour)
// drop(c);
assert_eq!(w.0, &3);
}
pub trait FamilyLt<'a> {
type Out: 'a;
}
pub struct RefFamily<T: Any>(PhantomData<T>);
impl<'a, T: 'a + Any> FamilyLt<'a> for RefFamily<T> {
type Out = T;
}
trait QueryTrait {
type Item: for<'a> FamilyLt<'a>;
}
struct Query<T: Any>(PhantomData<T>);
impl<T: Any> QueryTrait for Query<T> {
type Item = RefFamily<T>;
}
struct Wrapper<'a>(&'a i32);
struct Container(*const (), *const dyn Fn());
impl Container {
fn new(a: i32) -> Self {
let nr_pointer = Box::into_raw(Box::new(a));
let wrapper_generator: Box<dyn Fn() -> Wrapper<'static>> = Box::new(
|| Wrapper(unsafe {&*nr_pointer})
);
Container(nr_pointer as *const (), Box::into_raw(wrapper_generator) as *const dyn Fn())
}
fn get_second_as<'a, T: QueryTrait>(&'a self) -> <T::Item as FamilyLt<'a>>::Out {
let func_ptr = self.1 as *const dyn Fn() -> <T::Item as FamilyLt<'a>>::Out;
let ptr = unsafe { &* func_ptr };
(ptr)()
}
}
impl Drop for Container {
fn drop(&mut self) {
unsafe {
drop(Box::from_raw(self.0 as *mut i32));
drop(Box::from_raw(self.1 as *mut dyn Fn()));
}
}
}