use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use crate::PointerValuePair;
#[repr(transparent)]
pub struct Cow<'a, T> {
inner: PointerValuePair<T>,
_phantom: PhantomData<&'a T>,
}
const BORROWED: usize = 0usize;
const OWNED: usize = 1usize;
impl<'a, T> Cow<'a, T> {
pub fn borrowed(v: &'a T) -> Cow<'a, T> {
Cow {
inner: PointerValuePair::new(v, BORROWED),
_phantom: PhantomData,
}
}
pub fn owned(v: Box<T>) -> Cow<'a, T> {
Cow {
inner: PointerValuePair::new(Box::into_raw(v), OWNED),
_phantom: PhantomData,
}
}
}
impl<'a, T> Cow<'a, T> where T: Clone {
pub fn into_owned(self) -> Box<T> {
if self.inner.value() == OWNED {
let boxed = unsafe {
Box::from_raw(self.inner.ptr() as *mut T)
};
mem::forget(self);
boxed
} else {
Box::new(self.deref().clone())
}
}
pub fn into_owned_cow<'b>(self) -> Cow<'b, T> {
if self.inner.value() == OWNED {
let result = Cow {
inner: self.inner,
_phantom: Default::default()
};
mem::forget(self);
result
} else {
Cow::owned(Box::new(self.deref().clone()))
}
}
}
impl<'a, T> Drop for Cow<'a, T> {
fn drop(&mut self) {
unsafe {
if self.inner.value() == OWNED {
drop(Box::from_raw(self.inner.ptr() as *mut T))
}
}
}
}
impl<'a, T> Deref for Cow<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.inner.ptr() }
}
}
#[cfg(test)]
mod tests {
use std::cell::Cell;
use std::mem;
use crate::Cow;
#[test]
fn pointer_sized() {
assert_eq!(mem::size_of::<*const i32>(), mem::size_of::<Cow<'static,i32>>());
}
#[test]
fn owned_cow_drop() {
let drop_flag = Cell::new(false);
#[derive(Clone)]
struct DropTest<'a> {
flag: &'a Cell<bool>
}
impl<'a> Drop for DropTest<'a> {
fn drop(&mut self) {
self.flag.set(true)
}
}
{
let drop_test = DropTest { flag: &drop_flag };
let cow = Cow::owned(Box::new(drop_test));
let cow = cow.into_owned_cow();
assert!(!drop_flag.get());
let boxed = cow.into_owned();
assert!(!drop_flag.get());
let _cow = Cow::owned(boxed);
assert!(!drop_flag.get());
}
assert!(drop_flag.get());
}
}