use core::{
ops::{Deref, DerefMut},
ptr::NonNull,
};
use alloc::{boxed::Box, sync::Arc};
pub struct Cowarc<'a, T> {
inner: Inner<'a, T>,
}
impl<'a, T> Cowarc<'a, T> {
pub fn new_root(arc: &'a mut Arc<T>) -> Self {
Self {
inner: Inner::Root(arc),
}
}
pub unsafe fn new_child(
child: NonNull<T>,
map: Box<dyn FnMut() -> NonNull<T> + 'a>,
) -> Cowarc<'a, T>
where
T: Clone,
{
Cowarc {
inner: Inner::Child { this: child, map },
}
}
pub fn into_ref(cowarc: Self) -> &'a T
where
T: Clone,
{
match cowarc.inner {
Inner::Root(arc) => &*arc,
Inner::Child { this, .. } => unsafe { this.as_ref() },
}
}
pub fn into_mut(cowarc: Self) -> &'a mut T
where
T: Clone,
{
match cowarc.inner {
Inner::Root(arc) => Arc::make_mut(arc),
Inner::Child { mut map, .. } => unsafe { map().as_mut() },
}
}
}
impl<'a, T> Deref for Cowarc<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match &self.inner {
Inner::Root(arc) => &arc,
Inner::Child { this, .. } => unsafe { this.as_ref() },
}
}
}
impl<'a, T: Clone> DerefMut for Cowarc<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
match &mut self.inner {
Inner::Root(arc) => Arc::make_mut(arc),
Inner::Child { this, map, .. } => unsafe {
*this = map();
this.as_mut()
},
}
}
}
enum Inner<'a, T> {
Root(&'a mut Arc<T>),
Child {
this: NonNull<T>,
map: Box<dyn FnMut() -> NonNull<T> + 'a>,
},
}