varlen/
owned.rs

1//! A pointer to `T` that calls its destructor but not its deallocator when dropped.
2//!
3//! # Examples
4//!
5//! ```
6//! # #[cfg(feature = "bumpalo")] {
7//! use varlen::prelude::*;
8//! type TypeWithDrop = Tup2<FixedLen<Box<u32>>, Str>;
9//! let arena = bumpalo::Bump::new();
10//! let owned: Owned<TypeWithDrop> = Owned::new_in(
11//!     tup2::Init(
12//!         FixedLen(Box::new(42)),
13//!         Str::copy("hello")
14//!     ),
15//!     &arena);
16//! assert_eq!(42, *owned.refs().0.0);
17//! drop(owned); // Calls drop() on the Box<u32>
18//! drop(arena); // Deallocates the arena storage.
19//! # }
20//! ```
21use crate::Initializer;
22
23use super::{Layout, VarLen};
24
25use core::marker::PhantomData;
26use core::pin::Pin;
27use core::ptr::NonNull;
28
29/// A pointer to `T` that calls its destructor but not its deallocator when dropped.
30///
31/// # Examples
32///
33/// ```
34/// #[cfg(feature = "bumpalo")] {
35/// use varlen::prelude::*;
36/// type TypeWithDrop = Tup2<FixedLen<Box<u32>>, Str>;
37/// let arena = bumpalo::Bump::new();
38/// let owned: Owned<TypeWithDrop> = Owned::new_in(
39///     tup2::Init(
40///         FixedLen(Box::new(42)),
41///         Str::copy("hello")
42///     ),
43///     &arena);
44/// assert_eq!(42, *owned.refs().0.0);
45/// drop(owned); // Calls drop() on the Box<u32>
46/// drop(arena); // Deallocates the arena storage.
47/// }
48/// ```
49///
50/// # Comparison to `T` on fixed length types
51///
52/// The type [`Owned<T>`] fills a role for variable-length types similar to what `T` fills
53/// for fixed-length types, typically in "into" or "take" APIs. For example, whereas
54/// `Vec<T>::into_iter` iterates over `T` items (taking them and potentially dropping them
55/// one-by-one), [`crate::seq::Seq<T>::take_elems`] iterates over `Owned<T>` items, taking them and
56/// potentially dropping them one-by-bone:
57///
58/// ```
59/// use varlen::prelude::*;
60/// fn consume_seq<T: VarLen>(mut seq: Seq<T>) {
61///     for t in seq.take_elems() {
62///         let t: Owned<T> = t;
63///         // T's destructor runs here, freeing any memory it points to.
64///     }
65///     assert_eq!(0, seq.len());
66///     // Seq<T>'s destructor runs here, freeing its underlying storage.
67/// }
68/// ```
69pub struct Owned<'storage, T: VarLen>(NonNull<T>, PhantomData<&'storage [u8]>);
70
71#[allow(rustdoc::missing_doc_code_examples)]
72impl<'storage, T: VarLen> Owned<'storage, T> {
73    /// Constructs an `Owned<T>` pointer from a `NonNull<T>` pointer.
74    ///
75    /// # Safety
76    ///
77    /// The layout of `T`'s _tail_, which is the variable-sized part not included in
78    /// `std::mem::size_of::<T>()`, must be consistent with the layout specified by
79    /// `T`'s header. For example, this can have been produced by a
80    /// [`crate::Initializer<T>`] call or similar, on a buffer sufficiently sized for
81    /// the initializer's layout.
82    ///
83    /// # Example
84    ///
85    /// Safe roundtripping through a raw pointer:
86    ///
87    /// ```
88    /// use varlen::prelude::*;
89    /// fn roundtrip<T: VarLen>(x: Owned<T>) -> Owned<T> {
90    ///     unsafe {
91    ///         let p = x.into_raw();
92    ///         Owned::from_raw(p)
93    ///     }
94    /// }
95    /// ```
96    pub unsafe fn from_raw(raw: NonNull<T>) -> Self {
97        Owned(raw, PhantomData)
98    }
99
100    /// Converts this to a raw pointer representation.
101    ///
102    /// # Safety
103    ///
104    /// Because `T` is a variable-length type, there are additional safety obligations
105    /// above and beyond the usual treatment of `NonNull<T>`. In particular, the caller
106    /// responsible for ensuring that whenever a `&T` is produced, the header-specified
107    /// layout matches the layout of the tail. This prohibits code patterns such as
108    /// overwriting the header in a way that changes the layout.
109    ///
110    /// # Example
111    ///
112    /// Safe roundtripping through a raw pointer:
113    ///
114    /// ```
115    /// use varlen::prelude::*;
116    /// fn roundtrip<T: VarLen>(x: Owned<T>) -> Owned<T> {
117    ///     unsafe {
118    ///         let p = x.into_raw();
119    ///         Owned::from_raw(p)
120    ///     }
121    /// }
122    /// ```
123    pub unsafe fn into_raw(self) -> NonNull<T> {
124        let result = self.0;
125        core::mem::forget(self);
126        result
127    }
128
129    /// Gets a (pinned) mutable reference.
130    ///
131    /// # Example
132    ///
133    /// ```
134    /// # #[cfg(feature = "bumpalo")] {
135    /// use varlen::prelude::*;
136    /// use bumpalo::Bump;
137    ///
138    /// let arena = Bump::new();
139    /// let mut s = Owned::new_in(Str::copy("Hello"), &arena);
140    /// s.as_mut().mut_slice().make_ascii_uppercase();
141    /// assert_eq!("HELLO", &s[..]);
142    /// s.as_mut().mut_slice().make_ascii_lowercase();
143    /// assert_eq!("hello", &s[..]);
144    /// # }
145    /// ```
146    pub fn as_mut(&mut self) -> Pin<&mut T> {
147        unsafe { Pin::new_unchecked(self.0.as_mut()) }
148    }
149
150    /// Forgets the obligation to drop this.
151    ///
152    /// # Example
153    ///
154    /// ```
155    /// # #[cfg(feature = "bumpalo")] {
156    /// use bumpalo::Bump;
157    /// use varlen::prelude::*;
158    /// let arena = Bump::new();
159    /// let s = Owned::new_in(Str::copy("hello"), &arena);
160    /// let s = s.leak();
161    /// assert_eq!("hello", &s[..]);
162    /// # }
163    /// ```
164    pub fn leak(self) -> Pin<&'storage mut T> {
165        let Owned(mut ptr, _) = self;
166        unsafe { Pin::new_unchecked(ptr.as_mut()) }
167    }
168
169    /// Allocates a `T` on the arena.
170    ///
171    /// # Example
172    ///
173    /// ```
174    /// # #[cfg(feature = "bumpalo")] {
175    /// use bumpalo::Bump;
176    /// use varlen::prelude::*;
177    /// let arena = Bump::new();
178    /// let s = Owned::new_in(Str::copy("hello"), &arena);
179    /// assert_eq!("hello", &s[..]);
180    /// # }
181    /// ```
182    #[cfg(feature = "bumpalo")]
183    #[inline]
184    pub fn new_in(init: impl Initializer<T>, bump: &'storage bumpalo::Bump) -> Self {
185        use core::alloc;
186        let layout = init.calculate_layout_cautious().unwrap();
187        let ptr = bump
188            .alloc_layout(alloc::Layout::from_size_align(layout.size(), T::ALIGN).unwrap())
189            .cast::<T>();
190        unsafe {
191            init.initialize(ptr, layout);
192        }
193        Owned(ptr, PhantomData)
194    }
195}
196
197impl<T: VarLen> Drop for Owned<'_, T> {
198    fn drop(&mut self) {
199        unsafe {
200            // Safety: vdrop is called only once, because Self::drop() is called only once.
201            let layout = T::calculate_layout(&*self);
202            T::vdrop(self.as_mut(), layout);
203        }
204    }
205}
206
207impl<T: VarLen> core::ops::Deref for Owned<'_, T> {
208    type Target = T;
209    fn deref(&self) -> &T {
210        unsafe { self.0.as_ref() }
211    }
212}
213
214unsafe impl<T: VarLen> Initializer<T> for Owned<'_, T> {
215    unsafe fn initialize(self, dst: NonNull<T>, layout: T::Layout) {
216        // Safety:
217        //  * Owned has unique access to its pointer
218        //  * dst is unique
219        //  * dst size is guaranteed by the SizedInitializer call
220        core::ptr::copy_nonoverlapping(self.0.as_ptr(), dst.as_ptr(), layout.size());
221        core::mem::forget(self);
222    }
223
224    #[inline]
225    fn calculate_layout_cautious(&self) -> Option<T::Layout> {
226        Some(T::calculate_layout(&*self))
227    }
228}