beef/
traits.rs

1pub(crate) use internal::Beef;
2pub(crate) use internal::Capacity;
3
4pub(crate) mod internal {
5    use alloc::borrow::ToOwned;
6    use alloc::string::String;
7    use alloc::vec::Vec;
8    use core::mem::ManuallyDrop;
9    use core::ptr::{slice_from_raw_parts, NonNull};
10
11    pub trait Capacity {
12        type Field: Copy;
13        type NonZero: Copy;
14
15        fn len(fat: usize) -> usize;
16
17        fn empty(len: usize) -> (usize, Self::Field);
18
19        fn store(len: usize, capacity: usize) -> (usize, Self::Field);
20
21        fn unpack(fat: usize, capacity: Self::NonZero) -> (usize, usize);
22
23        fn maybe(fat: usize, capacity: Self::Field) -> Option<Self::NonZero>;
24    }
25
26    /// Helper trait required by `Cow<T>` to extract capacity of owned
27    /// variant of `T`, and manage conversions.
28    ///
29    /// This can be only implemented on types that match requirements:
30    ///
31    /// + `T::Owned` has a `capacity`, which is an extra word that is absent in `T`.
32    /// + `T::Owned` with `capacity` of `0` does not allocate memory.
33    /// + `T::Owned` can be reconstructed from `*mut T` borrowed out of it, plus capacity.
34    pub unsafe trait Beef: ToOwned {
35        type PointerT;
36
37        fn ref_into_parts<U>(&self) -> (NonNull<Self::PointerT>, usize, U::Field)
38        where
39            U: Capacity;
40
41        unsafe fn ref_from_parts<U>(ptr: NonNull<Self::PointerT>, len: usize) -> *const Self
42        where
43            U: Capacity;
44
45        /// Convert `T::Owned` to `NonNull<T>` and capacity.
46        /// Return `None` for `0` capacity.
47        fn owned_into_parts<U>(owned: Self::Owned) -> (NonNull<Self::PointerT>, usize, U::Field)
48        where
49            U: Capacity;
50
51        /// Rebuild `T::Owned` from `NonNull<T>` and `capacity`. This can be done by the likes
52        /// of [`Vec::from_raw_parts`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.from_raw_parts).
53        unsafe fn owned_from_parts<U>(
54            ptr: NonNull<Self::PointerT>,
55            fat: usize,
56            capacity: U::NonZero,
57        ) -> Self::Owned
58        where
59            U: Capacity;
60    }
61
62    unsafe impl Beef for str {
63        type PointerT = u8;
64
65        #[inline]
66        fn ref_into_parts<U>(&self) -> (NonNull<u8>, usize, U::Field)
67        where
68            U: Capacity,
69        {
70            let (fat, cap) = U::empty(self.len());
71
72            // A note on soundness:
73            //
74            // We are casting *const T to *mut T, however for all borrowed values
75            // this raw pointer is only ever dereferenced back to &T.
76            (
77                unsafe { NonNull::new_unchecked(self.as_ptr() as *mut u8) },
78                fat,
79                cap,
80            )
81        }
82
83        #[inline]
84        unsafe fn ref_from_parts<U>(ptr: NonNull<u8>, fat: usize) -> *const str
85        where
86            U: Capacity,
87        {
88            slice_from_raw_parts(ptr.as_ptr(), U::len(fat)) as *const str
89        }
90
91        #[inline]
92        fn owned_into_parts<U>(owned: String) -> (NonNull<u8>, usize, U::Field)
93        where
94            U: Capacity,
95        {
96            // Convert to `String::into_raw_parts` once stabilized
97            // We need to go through Vec here to get provenance for the entire allocation
98            // instead of just the initialized parts.
99            let mut owned = ManuallyDrop::new(owned.into_bytes());
100            let (fat, cap) = U::store(owned.len(), owned.capacity());
101
102            (
103                unsafe { NonNull::new_unchecked(owned.as_mut_ptr()) },
104                fat,
105                cap,
106            )
107        }
108
109        #[inline]
110        unsafe fn owned_from_parts<U>(ptr: NonNull<u8>, fat: usize, capacity: U::NonZero) -> String
111        where
112            U: Capacity,
113        {
114            let (len, cap) = U::unpack(fat, capacity);
115
116            String::from_utf8_unchecked(Vec::from_raw_parts(ptr.as_ptr(), len, cap))
117        }
118    }
119
120    unsafe impl<T: Clone> Beef for [T] {
121        type PointerT = T;
122
123        #[inline]
124        fn ref_into_parts<U>(&self) -> (NonNull<T>, usize, U::Field)
125        where
126            U: Capacity,
127        {
128            let (fat, cap) = U::empty(self.len());
129
130            // A note on soundness:
131            //
132            // We are casting *const T to *mut T, however for all borrowed values
133            // this raw pointer is only ever dereferenced back to &T.
134            (
135                unsafe { NonNull::new_unchecked(self.as_ptr() as *mut T) },
136                fat,
137                cap,
138            )
139        }
140
141        #[inline]
142        unsafe fn ref_from_parts<U>(ptr: NonNull<T>, fat: usize) -> *const [T]
143        where
144            U: Capacity,
145        {
146            slice_from_raw_parts(ptr.as_ptr(), U::len(fat))
147        }
148
149        #[inline]
150        fn owned_into_parts<U>(owned: Vec<T>) -> (NonNull<T>, usize, U::Field)
151        where
152            U: Capacity,
153        {
154            // Convert to `Vec::into_raw_parts` once stabilized
155            let mut owned = ManuallyDrop::new(owned);
156            let (fat, cap) = U::store(owned.len(), owned.capacity());
157
158            (
159                unsafe { NonNull::new_unchecked(owned.as_mut_ptr()) },
160                fat,
161                cap,
162            )
163        }
164
165        #[inline]
166        unsafe fn owned_from_parts<U>(ptr: NonNull<T>, fat: usize, capacity: U::NonZero) -> Vec<T>
167        where
168            U: Capacity,
169        {
170            let (len, cap) = U::unpack(fat, capacity);
171
172            Vec::from_raw_parts(ptr.as_ptr(), len, cap)
173        }
174    }
175}