simple_dst/lib.rs
1//! Traits and derive macros for allocating and using DSTs.
2//!
3//! The design is inspired by the great [slice-dst] crate, but with more of a
4//! focus on implementability and use of modern Rust features.
5//!
6//! Subject to breaking changes until the crate hits 1.0, which will only be possible
7//! once Rust stabilises the `ptr_metadata` and `clone_to_uninit` features.
8//!
9//! [slice-dst]: https://lib.rs/crates/slice-dst
10
11#![no_std]
12
13#[cfg(feature = "alloc")]
14extern crate alloc;
15
16#[cfg(test)]
17mod tests;
18
19#[cfg(feature = "alloc")]
20use alloc::{
21 alloc::{alloc, dealloc, handle_alloc_error},
22 boxed::Box,
23 rc::Rc,
24 sync::Arc,
25};
26use core::{
27 alloc::{Layout, LayoutError},
28 borrow::Borrow,
29 convert::Infallible,
30 mem::{self, MaybeUninit},
31 ptr::{self, NonNull},
32};
33
34#[cfg(feature = "simple-dst-derive")]
35pub use simple_dst_derive::{CloneToUninit, Dst, ToOwned};
36
37/// A dynamically sized type.
38///
39/// # Safety
40///
41/// Must be implemented as described.
42// FUTURE: switch to metadata rather than length once the `ptr_metadata` feature
43// has stabilised.
44pub unsafe trait Dst {
45 /// The length of the DST.
46 ///
47 /// Note that this is NOT the size of the type, for that you should use
48 /// [`Layout::for_value`] or [`Dst::layout`].
49 fn len(&self) -> usize;
50
51 /// Counterpart to `len`. Mainly exists to please clippy.
52 ///
53 /// The default implementation simply checks if the len equals 0.
54 fn is_empty(&self) -> bool {
55 self.len() == 0
56 }
57
58 /// Returns the layout of the DST, assuming it has the given length.
59 ///
60 /// # Errors
61 ///
62 /// Returns a [`LayoutError`] if calculation of the layout fails.
63 fn layout(len: usize) -> Result<Layout, LayoutError>;
64
65 /// Convert the given thin pointer to a fat pointer to the DST, adding the
66 /// length to the metadata.
67 ///
68 /// # Safety
69 ///
70 /// This function is safe but the returned pointer is not necessarily safe
71 /// to dereference.
72 // FUTURE: won't be necessary once `ptr_metadata` has been stabilised.
73 fn retype(ptr: NonNull<u8>, len: usize) -> NonNull<Self>;
74}
75
76// SAFETY: implemented correctly.
77unsafe impl<T> Dst for [T] {
78 fn len(&self) -> usize {
79 self.len()
80 }
81
82 fn layout(len: usize) -> Result<Layout, LayoutError> {
83 Layout::array::<T>(len)
84 }
85
86 fn retype(ptr: NonNull<u8>, len: usize) -> NonNull<Self> {
87 NonNull::slice_from_raw_parts(ptr.cast(), len)
88 }
89}
90
91// SAFETY: implemented correctly.
92unsafe impl Dst for str {
93 fn len(&self) -> usize {
94 self.len()
95 }
96
97 fn layout(len: usize) -> Result<Layout, LayoutError> {
98 Layout::array::<u8>(len)
99 }
100
101 fn retype(ptr: NonNull<u8>, len: usize) -> NonNull<Self> {
102 // FUTURE: switch to ptr::from_raw_parts_mut() when it has stabilised.
103 // SAFETY: the pointer value doesn't change when using `slice_from_raw_parts_mut`,
104 // so the invariants of `NonNull` are upheld
105 unsafe {
106 NonNull::new_unchecked(ptr::slice_from_raw_parts_mut(ptr.as_ptr(), len) as *mut Self)
107 }
108 }
109}
110
111// Copied from the unstable standard library's implementation.
112/// A generalization of [`Clone`] to [dynamically-sized types][DST] stored in arbitrary containers.
113///
114/// This trait is implemented for all types implementing [`Clone`], [slices](slice) of all
115/// such types, and other dynamically-sized types in the standard library.
116/// You may also implement this trait to enable cloning custom DSTs
117/// (structures containing dynamically-sized fields), or use it as a supertrait to enable
118/// cloning a [trait object].
119///
120/// This trait is normally used via operations on container types which support DSTs,
121/// so you should not typically need to call `.clone_to_uninit()` explicitly except when
122/// implementing such a container or otherwise performing explicit management of an allocation,
123/// or when implementing `CloneToUninit` itself.
124///
125/// # Safety
126///
127/// Implementations must ensure that when `.clone_to_uninit(dest)` returns normally rather than
128/// panicking, it always leaves `*dest` initialized as a valid value of type `Self`.
129///
130/// # Examples
131///
132/// If you are defining a trait, you can add `CloneToUninit` as a supertrait to enable cloning of
133/// `dyn` values of your trait:
134///
135/// ```ignore
136/// #![feature(clone_to_uninit)]
137/// use std::rc::Rc;
138///
139/// trait Foo: std::fmt::Debug + std::clone::CloneToUninit {
140/// fn modify(&mut self);
141/// fn value(&self) -> i32;
142/// }
143///
144/// impl Foo for i32 {
145/// fn modify(&mut self) {
146/// *self *= 10;
147/// }
148/// fn value(&self) -> i32 {
149/// *self
150/// }
151/// }
152///
153/// let first: Rc<dyn Foo> = Rc::new(1234);
154///
155/// let mut second = first.clone();
156/// Rc::make_mut(&mut second).modify(); // make_mut() will call clone_to_uninit()
157///
158/// assert_eq!(first.value(), 1234);
159/// assert_eq!(second.value(), 12340);
160/// ```
161///
162/// The following is an example of implementing `CloneToUninit` for a custom DST.
163/// (It is essentially a limited form of what `derive(CloneToUninit)` would do,
164/// if such a derive macro existed.)
165///
166/// ```ignore
167/// #![feature(clone_to_uninit)]
168/// use std::clone::CloneToUninit;
169/// use std::mem::offset_of;
170/// use std::rc::Rc;
171///
172/// #[derive(PartialEq)]
173/// struct MyDst<T: ?Sized> {
174/// label: String,
175/// contents: T,
176/// }
177///
178/// unsafe impl<T: ?Sized + CloneToUninit> CloneToUninit for MyDst<T> {
179/// unsafe fn clone_to_uninit(&self, dest: *mut u8) {
180/// // The offset of `self.contents` is dynamic because it depends on the alignment of T
181/// // which can be dynamic (if `T = dyn SomeTrait`). Therefore, we have to obtain it
182/// // dynamically by examining `self`, rather than using `offset_of!`.
183/// //
184/// // SAFETY: `self` by definition points somewhere before `&self.contents` in the same
185/// // allocation.
186/// let offset_of_contents = unsafe {
187/// (&raw const self.contents).byte_offset_from_unsigned(self)
188/// };
189///
190/// // Clone the *sized* fields of `self` (just one, in this example).
191/// // (By cloning this first and storing it temporarily in a local variable, we avoid
192/// // leaking it in case of any panic, using the ordinary automatic cleanup of local
193/// // variables. Such a leak would be sound, but undesirable.)
194/// let label = self.label.clone();
195///
196/// // SAFETY: The caller must provide a `dest` such that these field offsets are valid
197/// // to write to.
198/// unsafe {
199/// // Clone the unsized field directly from `self` to `dest`.
200/// self.contents.clone_to_uninit(dest.add(offset_of_contents));
201///
202/// // Now write all the sized fields.
203/// //
204/// // Note that we only do this once all of the clone() and clone_to_uninit() calls
205/// // have completed, and therefore we know that there are no more possible panics;
206/// // this ensures no memory leaks in case of panic.
207/// dest.add(offset_of!(Self, label)).cast::<String>().write(label);
208/// }
209/// // All fields of the struct have been initialized; therefore, the struct is initialized,
210/// // and we have satisfied our `unsafe impl CloneToUninit` obligations.
211/// }
212/// }
213///
214/// fn main() {
215/// // Construct MyDst<[u8; 4]>, then coerce to MyDst<[u8]>.
216/// let first: Rc<MyDst<[u8]>> = Rc::new(MyDst {
217/// label: String::from("hello"),
218/// contents: [1, 2, 3, 4],
219/// });
220///
221/// let mut second = first.clone();
222/// // make_mut() will call clone_to_uninit().
223/// for elem in Rc::make_mut(&mut second).contents.iter_mut() {
224/// *elem *= 10;
225/// }
226///
227/// assert_eq!(first.contents, [1, 2, 3, 4]);
228/// assert_eq!(second.contents, [10, 20, 30, 40]);
229/// assert_eq!(second.label, "hello");
230/// }
231/// ```
232///
233/// # See Also
234///
235/// * [`Clone::clone_from`] is a safe function which may be used instead when [`Self: Sized`](Sized)
236/// and the destination is already initialized; it may be able to reuse allocations owned by
237/// the destination, whereas `clone_to_uninit` cannot, since its destination is assumed to be
238/// uninitialized.
239/// * [`ToOwned`], which allocates a new destination container.
240///
241/// [`ToOwned`]: ../../std/borrow/trait.ToOwned.html
242/// [DST]: https://doc.rust-lang.org/reference/dynamically-sized-types.html
243/// [trait object]: https://doc.rust-lang.org/reference/types/trait-object.html
244// FUTURE: switch to `CloneToUninit` when it is stabilised.
245pub unsafe trait CloneToUninit {
246 /// Performs copy-assignment from `self` to `dest`.
247 ///
248 /// This is analogous to `std::ptr::write(dest.cast(), self.clone())`,
249 /// except that `Self` may be a dynamically-sized type ([`!Sized`](Sized)).
250 ///
251 /// Before this function is called, `dest` may point to uninitialized memory.
252 /// After this function is called, `dest` will point to initialized memory; it will be
253 /// sound to create a `&Self` reference from the pointer with the [pointer metadata]
254 /// from `self`.
255 ///
256 /// # Safety
257 ///
258 /// Behavior is undefined if any of the following conditions are violated:
259 ///
260 /// * `dest` must be [valid] for writes for `size_of_val(self)` bytes.
261 /// * `dest` must be properly aligned to `align_of_val(self)`.
262 ///
263 /// [valid]: crate::ptr#safety
264 /// [pointer metadata]: crate::ptr::metadata()
265 ///
266 /// # Panics
267 ///
268 /// This function may panic. (For example, it might panic if memory allocation for a clone
269 /// of a value owned by `self` fails.)
270 /// If the call panics, then `*dest` should be treated as uninitialized memory; it must not be
271 /// read or dropped, because even if it was previously valid, it may have been partially
272 /// overwritten.
273 ///
274 /// The caller may wish to take care to deallocate the allocation pointed to by `dest`,
275 /// if applicable, to avoid a memory leak (but this is not a requirement).
276 ///
277 /// Implementors should avoid leaking values by, upon unwinding, dropping all component values
278 /// that might have already been created. (For example, if a `[Foo]` of length 3 is being
279 /// cloned, and the second of the three calls to `Foo::clone()` unwinds, then the first `Foo`
280 /// cloned should be dropped.)
281 unsafe fn clone_to_uninit(&self, dest: *mut u8);
282}
283
284// SAFETY: implemented correctly.
285unsafe impl<T: Clone> CloneToUninit for T {
286 #[inline]
287 unsafe fn clone_to_uninit(&self, dest: *mut u8) {
288 // SAFETY: `dest` is required to be valid for writes of type T by the contract
289 // specified by the trait.
290 unsafe {
291 // We hope the optimizer will figure out to create the cloned value in-place,
292 // skipping ever storing it on the stack and the copy to the destination.
293 dest.cast::<Self>().write(self.clone());
294 }
295 }
296}
297
298// SAFETY: implemented correctly.
299unsafe impl<T: Clone> CloneToUninit for [T] {
300 // Copied from the standard library's implementation.
301 unsafe fn clone_to_uninit(&self, dest: *mut u8) {
302 /// Ownership of a collection of values stored in a non-owned `[MaybeUninit<T>]`, some of which
303 /// are not yet initialized. This is sort of like a `Vec` that doesn't own its allocation.
304 /// Its responsibility is to provide cleanup on unwind by dropping the values that *are*
305 /// initialized, unless disarmed by forgetting.
306 ///
307 /// This is a helper for `impl<T: Clone> CloneToUninit for [T]`.
308 struct InitializingSlice<'a, T> {
309 data: &'a mut [MaybeUninit<T>],
310 /// Number of elements of `*self.data` that are initialized.
311 initialized_len: usize,
312 }
313
314 impl<'a, T> InitializingSlice<'a, T> {
315 #[inline]
316 fn from_fully_uninit(data: &'a mut [MaybeUninit<T>]) -> Self {
317 Self {
318 data,
319 initialized_len: 0,
320 }
321 }
322
323 /// Push a value onto the end of the initialized part of the slice.
324 ///
325 /// # Panics
326 ///
327 /// Panics if the slice is already fully initialized.
328 #[inline]
329 fn push(&mut self, value: T) {
330 #[allow(
331 clippy::indexing_slicing,
332 reason = "the possibility of panicking is documented above"
333 )]
334 MaybeUninit::write(&mut self.data[self.initialized_len], value);
335 self.initialized_len += 1;
336 }
337 }
338
339 impl<T> Drop for InitializingSlice<'_, T> {
340 #[cold] // will only be invoked on unwind
341 fn drop(&mut self) {
342 #[allow(
343 clippy::indexing_slicing,
344 reason = "the indexing can't panic, as documented by the SAFETY comment"
345 )]
346 // SAFETY:
347 // * the pointer is valid because it was made from a mutable reference
348 // * `initialized_len` counts the initialized elements as an invariant of this type,
349 // so each of the pointed-to elements is initialized and may be dropped.
350 unsafe {
351 self.data[..self.initialized_len].assume_init_drop();
352 }
353 }
354 }
355
356 let len = self.len();
357 let dest = ptr::slice_from_raw_parts_mut(dest.cast::<T>(), len);
358 // This is the most likely mistake to make, so check it as a debug assertion.
359 debug_assert_eq!(
360 len,
361 dest.len(),
362 "clone_to_uninit() source and destination must have equal lengths",
363 );
364
365 // SAFETY: The produced `&mut` is valid because:
366 // * The caller is obligated to provide a pointer which is valid for writes.
367 // * All bytes pointed to are in MaybeUninit, so we don't care about the memory's
368 // initialization status.
369 let uninit_ref = unsafe { &mut *(dest as *mut [MaybeUninit<T>]) };
370
371 // Copy the elements
372 let mut initializing = InitializingSlice::from_fully_uninit(uninit_ref);
373 for element_ref in self {
374 // If the clone() panics, `initializing` will take care of the cleanup.
375 initializing.push(element_ref.clone());
376 }
377 // If we reach here, then the entire slice is initialized, and we've satisfied our
378 // responsibilities to the caller. Disarm the cleanup guard by forgetting it.
379 mem::forget(initializing);
380 }
381}
382
383// SAFETY: implemented correctly.
384unsafe impl CloneToUninit for str {
385 #[inline]
386 unsafe fn clone_to_uninit(&self, dest: *mut u8) {
387 // SAFETY: str is just a [u8] with UTF-8 invariant
388 unsafe { self.as_bytes().clone_to_uninit(dest) }
389 }
390}
391
392// SAFETY: implemented correctly.
393unsafe impl CloneToUninit for core::ffi::CStr {
394 unsafe fn clone_to_uninit(&self, dest: *mut u8) {
395 // SAFETY: For now, CStr is just a #[repr(trasnsparent)] [c_char] with some invariants.
396 // And we can cast [c_char] to [u8] on all supported platforms (see: to_bytes_with_nul).
397 // The pointer metadata properly preserves the length (so NUL is also copied).
398 // See: `cstr_metadata_is_length_with_nul` in tests.
399 unsafe { self.to_bytes_with_nul().clone_to_uninit(dest) }
400 }
401}
402
403/// Type that can allocate a DST and store it inside it.
404///
405/// # Safety
406///
407/// Must be implemented as described.
408// FUTURE: use the Allocator trait once it has stabilised.
409pub unsafe trait AllocDst<T: ?Sized + Dst>: Sized + Borrow<T> {
410 /// Allocate the DST with the given length, initialize the data with the given
411 /// fallible function, and store it in the type.
412 ///
413 /// # Safety
414 ///
415 /// The `layout` must accurately describe an object of type T with length `len`.
416 /// The `init` function must correctly initialize the data pointed to, or return an
417 /// error.
418 ///
419 /// # Errors
420 ///
421 /// This function will only return an error in the case that the `init` function
422 /// returns an error.
423 unsafe fn try_new_dst<F, E>(len: usize, layout: Layout, init: F) -> Result<Self, E>
424 where
425 F: FnOnce(NonNull<T>) -> Result<(), E>;
426
427 /// Allocate the DST with the given length, initialize the data with the
428 /// given function, and store it in the type.
429 ///
430 /// # Safety
431 ///
432 /// The `layout` must accurately describe an object of type T with length `len`.
433 /// The `init` function must correctly initialize the data pointed to.
434 unsafe fn new_dst<F>(len: usize, layout: Layout, init: F) -> Self
435 where
436 F: FnOnce(NonNull<T>),
437 {
438 // SAFETY: simply defers to the provided `init` function, so the responsibility
439 // for maintaining safety is still on the caller.
440 let Ok(a) = unsafe {
441 Self::try_new_dst::<_, Infallible>(len, layout, |ptr| {
442 init(ptr);
443 Ok(())
444 })
445 };
446 a
447 }
448}
449
450#[cfg(feature = "alloc")]
451// SAFETY: implemented correctly.
452unsafe impl<T: ?Sized + Dst> AllocDst<T> for Box<T> {
453 unsafe fn try_new_dst<F, E>(len: usize, layout: Layout, init: F) -> Result<Self, E>
454 where
455 F: FnOnce(NonNull<T>) -> Result<(), E>,
456 {
457 struct RawBox<T: ?Sized + Dst>(ptr::NonNull<T>, Layout);
458
459 impl<T: ?Sized + Dst> RawBox<T> {
460 fn new(len: usize, layout: Layout) -> Self {
461 let ptr = if layout.size() == 0 {
462 layout.dangling_ptr()
463 } else {
464 // SAFETY: the layout's size is non-zero due to the if-statement.
465 NonNull::new(unsafe { alloc(layout) })
466 .unwrap_or_else(|| handle_alloc_error(layout))
467 };
468 let ptr = T::retype(ptr, len);
469
470 Self(ptr, layout)
471 }
472 }
473
474 impl<T: ?Sized + Dst> Drop for RawBox<T> {
475 fn drop(&mut self) {
476 if self.1.size() != 0 {
477 // SAFETY: the pointer is allocated by `alloc` in `new`, and the
478 // layout is the same.
479 unsafe {
480 dealloc(self.0.cast().as_ptr(), self.1);
481 };
482 }
483 }
484 }
485
486 let raw = RawBox::new(len, layout);
487 init(raw.0)?;
488 // SAFETY: the pointer is either a pointer to valid initialised allocated data,
489 // or a dangling pointer in the case that `T` is zero-sized, which are the
490 // memory requirements for `Box`.
491 let b = unsafe { Box::from_raw(raw.0.as_ptr()) };
492 mem::forget(raw);
493 Ok(b)
494 }
495}
496
497#[cfg(feature = "alloc")]
498// SAFETY: implemented correctly.
499unsafe impl<T: ?Sized + Dst> AllocDst<T> for Rc<T> {
500 unsafe fn try_new_dst<F, E>(len: usize, layout: Layout, init: F) -> Result<Self, E>
501 where
502 F: FnOnce(NonNull<T>) -> Result<(), E>,
503 {
504 // TODO: this allocates memory twice because Rc needs to store data in front of the data
505 // pointer. Find a way to only allocate once.
506 // SAFETY: the values from the caller are simply passed on to another
507 // implementer of the same trait, so the requirements are the same.
508 Ok(Self::from(unsafe { Box::try_new_dst(len, layout, init) }?))
509 }
510}
511
512#[cfg(feature = "alloc")]
513// SAFETY: implemented correctly.
514unsafe impl<T: ?Sized + Dst> AllocDst<T> for Arc<T> {
515 unsafe fn try_new_dst<F, E>(len: usize, layout: Layout, init: F) -> Result<Self, E>
516 where
517 F: FnOnce(NonNull<T>) -> Result<(), E>,
518 {
519 // TODO: this allocates memory twice because Arc needs to store data in front of the data
520 // pointer. Find a way to only allocate once.
521 // SAFETY: the values from the caller are simply passed on to another
522 // implementer of the same trait, so the requirements are the same.
523 Ok(Self::from(unsafe { Box::try_new_dst(len, layout, init) }?))
524 }
525}