pointer_value_pair/
cow.rs1use std::marker::PhantomData;
2use std::mem;
3use std::ops::Deref;
4use crate::PointerValuePair;
5
6#[repr(transparent)]
14pub struct Cow<'a, T> {
15 inner: PointerValuePair<T>,
16 _phantom: PhantomData<&'a T>,
17}
18
19const BORROWED: usize = 0usize;
20const OWNED: usize = 1usize;
21
22impl<'a, T> Cow<'a, T> {
23 pub fn borrowed(v: &'a T) -> Cow<'a, T> {
25 Cow {
26 inner: PointerValuePair::new(v, BORROWED),
27 _phantom: PhantomData,
28 }
29 }
30
31 pub fn owned(v: Box<T>) -> Cow<'a, T> {
33 Cow {
34 inner: PointerValuePair::new(Box::into_raw(v), OWNED),
35 _phantom: PhantomData,
36 }
37 }
38}
39
40impl<'a, T> Cow<'a, T> where T: Clone {
41 pub fn into_owned(self) -> Box<T> {
43 if self.inner.value() == OWNED {
44 let boxed = unsafe {
45 Box::from_raw(self.inner.ptr() as *mut T)
48 };
49 mem::forget(self);
51 boxed
52 } else {
53 Box::new(self.deref().clone())
54 }
55 }
56
57 pub fn into_owned_cow<'b>(self) -> Cow<'b, T> {
59 if self.inner.value() == OWNED {
60 let result = Cow {
62 inner: self.inner,
63 _phantom: Default::default()
64 };
65 mem::forget(self);
67 result
68 } else {
69 Cow::owned(Box::new(self.deref().clone()))
70 }
71 }
72}
73
74
75impl<'a, T> Drop for Cow<'a, T> {
76 fn drop(&mut self) {
77 unsafe {
78 if self.inner.value() == OWNED {
79 drop(Box::from_raw(self.inner.ptr() as *mut T))
80 }
81 }
82 }
83}
84
85impl<'a, T> Deref for Cow<'a, T> {
86 type Target = T;
87
88 fn deref(&self) -> &Self::Target {
89 unsafe { &*self.inner.ptr() }
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use std::cell::Cell;
98 use std::mem;
99 use crate::Cow;
100
101 #[test]
102 fn pointer_sized() {
103 assert_eq!(mem::size_of::<*const i32>(), mem::size_of::<Cow<'static,i32>>());
104 }
105
106 #[test]
107 fn owned_cow_drop() {
108 let drop_flag = Cell::new(false);
109
110 #[derive(Clone)]
111 struct DropTest<'a> {
112 flag: &'a Cell<bool>
113 }
114
115 impl<'a> Drop for DropTest<'a> {
116 fn drop(&mut self) {
117 self.flag.set(true)
118 }
119 }
120
121 {
122 let drop_test = DropTest { flag: &drop_flag };
123 let cow = Cow::owned(Box::new(drop_test));
124 let cow = cow.into_owned_cow();
125 assert!(!drop_flag.get());
126 let boxed = cow.into_owned();
127 assert!(!drop_flag.get());
128 let _cow = Cow::owned(boxed);
129 assert!(!drop_flag.get());
130 }
131
132 assert!(drop_flag.get());
133 }
134}