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