use std::{
mem::ManuallyDrop,
ops::{Deref, DerefMut},
};
pub struct Borrowed<O, V> {
view: ManuallyDrop<V>,
owner: ManuallyDrop<O>,
}
impl<O, V> Borrowed<O, V> {
pub unsafe fn new_unchecked(owner: O, view: V) -> Self {
Self {
view: ManuallyDrop::new(view),
owner: ManuallyDrop::new(owner),
}
}
pub fn owner(&self) -> &O {
&self.owner
}
pub fn view(&self) -> &V {
&self.view
}
pub fn view_mut(&mut self) -> &mut V {
&mut self.view
}
}
impl<O, V> Deref for Borrowed<O, V> {
type Target = V;
fn deref(&self) -> &Self::Target {
self.view()
}
}
impl<O, V> DerefMut for Borrowed<O, V> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.view_mut()
}
}
impl<O, V> Drop for Borrowed<O, V> {
fn drop(&mut self) {
unsafe {
ManuallyDrop::drop(&mut self.view);
ManuallyDrop::drop(&mut self.owner);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::{cell::RefCell, rc::Rc};
struct Tracked {
name: &'static str,
drops: Rc<RefCell<Vec<&'static str>>>,
}
impl Drop for Tracked {
fn drop(&mut self) {
self.drops.borrow_mut().push(self.name);
}
}
#[test]
fn drops_view_before_owner() {
let drops = Rc::new(RefCell::new(Vec::new()));
let owner = Tracked {
name: "owner",
drops: drops.clone(),
};
let view = Tracked {
name: "view",
drops: drops.clone(),
};
drop(unsafe { Borrowed::new_unchecked(owner, view) });
assert_eq!(&*drops.borrow(), &["view", "owner"]);
}
}