dairy/imp/compact/
mod.rs

1//! A better `Cow` implementation.
2
3mod convert;
4mod extent;
5
6use core::marker::PhantomData;
7use core::mem::ManuallyDrop;
8use core::ptr::NonNull;
9
10use crate::imp;
11use crate::imp::Cow as _;
12
13use self::convert::{Convert, IsOwned};
14
15/// A compact clone-on-write smart pointer.
16pub struct Cow<'a, T>
17where
18    T: ?Sized + Convert,
19{
20    /// Pointer to the data.
21    ptr: NonNull<T::Ptr>,
22
23    /// Any extra data that is required to reconstruct an owned or borrowed
24    /// variant of this type. For example: length and capacity.
25    extent: T::Extent,
26
27    /// For the lifetime.
28    marker: PhantomData<&'a T>,
29}
30
31impl<'a, T> imp::Cow<'a, T> for Cow<'a, T>
32where
33    T: ?Sized + Convert,
34{
35    #[inline]
36    fn borrowed(b: &'a T) -> Self {
37        let (ptr, extent) = T::unmake_borrowed(b);
38        Self {
39            ptr,
40            extent,
41            marker: PhantomData,
42        }
43    }
44
45    #[inline]
46    fn owned(o: T::Owned) -> Self {
47        let (ptr, extent) = T::unmake_owned(o);
48        Self {
49            ptr,
50            extent,
51            marker: PhantomData,
52        }
53    }
54
55    #[inline]
56    fn is_borrowed(&self) -> bool {
57        !self.extent.is_owned()
58    }
59
60    #[inline]
61    fn is_owned(&self) -> bool {
62        self.extent.is_owned()
63    }
64
65    #[inline]
66    fn make_ref(&self) -> &T {
67        // SAFETY: This is valid for both owned and borrowed variants.
68        unsafe { &*T::make_ptr(self.ptr, self.extent) }
69    }
70
71    #[inline]
72    fn into_owned(self) -> T::Owned {
73        if self.is_owned() {
74            let cow = ManuallyDrop::new(self);
75            unsafe { T::make_owned(cow.ptr, cow.extent) }
76        } else {
77            self.make_ref().to_owned()
78        }
79    }
80
81    #[inline]
82    fn apply<F>(&mut self, f: F)
83    where
84        F: FnOnce(&mut T::Owned),
85    {
86        let mut o = if self.is_owned() {
87            // SAFETY:  This is safe because we temporarily set the `extent` to
88            // its default value which should encode a "borrowed" version.
89            // Therefore, if `f` had to panic, no double drop would occur.
90            let o = unsafe { T::make_owned(self.ptr, self.extent) };
91            self.extent = T::Extent::default();
92            o
93        } else {
94            self.make_ref().to_owned()
95        };
96        f(&mut o);
97        let (ptr, extent) = T::unmake_owned(o);
98        self.ptr = ptr;
99        self.extent = extent;
100    }
101}
102
103impl<T> Clone for Cow<'_, T>
104where
105    T: ?Sized + Convert,
106{
107    #[inline]
108    fn clone(&self) -> Self {
109        if self.is_owned() {
110            Self::owned(self.make_ref().to_owned())
111        } else {
112            Self { ..*self }
113        }
114    }
115}
116
117impl<T> Drop for Cow<'_, T>
118where
119    T: ?Sized + Convert,
120{
121    #[inline]
122    fn drop(&mut self) {
123        if self.is_owned() {
124            unsafe { T::make_owned(self.ptr, self.extent) };
125        }
126    }
127}