I wrote a little module (playground) inspired by owning_ref for safely using raw pointers. The idea is that it's always safe, because the borrow checker won't let the dereferenced values escape the closure. Does this make sense?
mod r {
#[derive(Copy, Clone)]
pub struct OwnedRef<T>{
val: *const T
}
impl<T> std::ops::Deref for OwnedRef<T> {
type Target = T;
fn deref<'a>(&'a self) -> &'a Self::Target {
unsafe {
&*self.val
}
}
}
impl<T> OwnedRef<T> {
pub fn map<'a, U>(&'a self, f: fn(&'a T) -> &'a U) -> OwnedRef<U> {
OwnedRef{ val: &*f(&**self) }
}
}
impl<T> std::fmt::Debug for OwnedRef<T> where T: std::fmt::Debug {
// ...
}
pub struct WithRefs<O, T> {
owner: Box<O>,
data: T,
}
impl<O> WithRefs<O, OwnedRef<O>> {
pub fn new(owner: O) -> Self {
let boxed = Box::into_raw(Box::new(owner));
let reffed = OwnedRef::<O>{val: boxed};
unsafe {
WithRefs{ owner: Box::from_raw(boxed), data: reffed }
}
}
}
impl<O, T> WithRefs<O, T> {
pub fn map<F, U>(self, f: F) -> WithRefs<O, U>
where F: for<'a> FnOnce(&'a T) -> U {
let data1 = f(&self.data);
WithRefs{ owner: self.owner, data: data1 }
}
pub fn with_mut<F>(&mut self, f: F)
where F: for<'a> FnOnce(&'a mut T) {
f(&mut self.data);
}
pub fn with<F>(&self, f: F)
where F: for<'a> FnOnce(&'a T) {
f(&self.data);
}
}
}
// Example
struct Foo{f: f32, b: u32}
pub fn main() {
let a = r::WithRefs::new(5);
let mut b = a.map(|r| vec![*r]);
b.with_mut(|v| v.push(v[0]));
b.with(|v| println!("{:?}", v));
let c = r::WithRefs::new(Foo{ f: 3.0, b: 6 });
let d = c.map(|r| (r.map(|foo| &foo.f), r.map(|foo| &foo.b)));
d.with(|v| println!("{:?}", v));
}
then it's ok? It's a bit surprising to me that that this follows the aliasing rules, but it is what owning ref does. Is it ok because any time you examine the referent, you have to borrow or move out of self and thus the box?
Furthermore, owning_ref::map is also unsound in other ways
I'm on mobile right now, so I'm can't really test it, but your API might have the same flaw. (Note that there's even more open soundness issues on the owning_ref repository.)
Judging by the amount of soundness issues that I've seen reported on and even found myself in crates offering self-referential struct functionality, I can tell you: getting something like this right is notoriously hard, even for quite experienced Rust users.