Skip to main content

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}