2432 lines · 77.7 KB · Rust
RawDownload
// SPDX-License-Identifier: Apache-2.0 OR MIT //! The `Box<T>` type for heap allocation.//!//! [`Box<T>`], casually referred to as a 'box', provides the simplest form of//! heap allocation in Rust. Boxes provide ownership for this allocation, and//! drop their contents when they go out of scope. Boxes also ensure that they//! never allocate more than `isize::MAX` bytes.//!//! # Examples//!//! Move a value from the stack to the heap by creating a [`Box`]://!//! ```//! let val: u8 = 5;//! let boxed: Box<u8> = Box::new(val);//! ```//!//! Move a value from a [`Box`] back to the stack by [dereferencing]://!//! ```//! let boxed: Box<u8> = Box::new(5);//! let val: u8 = *boxed;//! ```//!//! Creating a recursive data structure://!//! ```//! #[derive(Debug)]//! enum List<T> {//!     Cons(T, Box<List<T>>),//!     Nil,//! }//!//! let list: List<i32> = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));//! println!("{list:?}");//! ```//!//! This will print `Cons(1, Cons(2, Nil))`.//!//! Recursive structures must be boxed, because if the definition of `Cons`//! looked like this://!//! ```compile_fail,E0072//! # enum List<T> {//! Cons(T, List<T>),//! # }//! ```//!//! It wouldn't work. This is because the size of a `List` depends on how many//! elements are in the list, and so we don't know how much memory to allocate//! for a `Cons`. By introducing a [`Box<T>`], which has a defined size, we know how//! big `Cons` needs to be.//!//! # Memory layout//!//! For non-zero-sized values, a [`Box`] will use the [`Global`] allocator for//! its allocation. It is valid to convert both ways between a [`Box`] and a//! raw pointer allocated with the [`Global`] allocator, given that the//! [`Layout`] used with the allocator is correct for the type. More precisely,//! a `value: *mut T` that has been allocated with the [`Global`] allocator//! with `Layout::for_value(&*value)` may be converted into a box using//! [`Box::<T>::from_raw(value)`]. Conversely, the memory backing a `value: *mut//! T` obtained from [`Box::<T>::into_raw`] may be deallocated using the//! [`Global`] allocator with [`Layout::for_value(&*value)`].//!//! For zero-sized values, the `Box` pointer still has to be [valid] for reads//! and writes and sufficiently aligned. In particular, casting any aligned//! non-zero integer literal to a raw pointer produces a valid pointer, but a//! pointer pointing into previously allocated memory that since got freed is//! not valid. The recommended way to build a Box to a ZST if `Box::new` cannot//! be used is to use [`ptr::NonNull::dangling`].//!//! So long as `T: Sized`, a `Box<T>` is guaranteed to be represented//! as a single pointer and is also ABI-compatible with C pointers//! (i.e. the C type `T*`). This means that if you have extern "C"//! Rust functions that will be called from C, you can define those//! Rust functions using `Box<T>` types, and use `T*` as corresponding//! type on the C side. As an example, consider this C header which//! declares functions that create and destroy some kind of `Foo`//! value://!//! ```c//! /* C header *///!//! /* Returns ownership to the caller *///! struct Foo* foo_new(void);//!//! /* Takes ownership from the caller; no-op when invoked with null *///! void foo_delete(struct Foo*);//! ```//!//! These two functions might be implemented in Rust as follows. Here, the//! `struct Foo*` type from C is translated to `Box<Foo>`, which captures//! the ownership constraints. Note also that the nullable argument to//! `foo_delete` is represented in Rust as `Option<Box<Foo>>`, since `Box<Foo>`//! cannot be null.//!//! ```//! #[repr(C)]//! pub struct Foo;//!//! #[no_mangle]//! pub extern "C" fn foo_new() -> Box<Foo> {//!     Box::new(Foo)//! }//!//! #[no_mangle]//! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}//! ```//!//! Even though `Box<T>` has the same representation and C ABI as a C pointer,//! this does not mean that you can convert an arbitrary `T*` into a `Box<T>`//! and expect things to work. `Box<T>` values will always be fully aligned,//! non-null pointers. Moreover, the destructor for `Box<T>` will attempt to//! free the value with the global allocator. In general, the best practice//! is to only use `Box<T>` for pointers that originated from the global//! allocator.//!//! **Important.** At least at present, you should avoid using//! `Box<T>` types for functions that are defined in C but invoked//! from Rust. In those cases, you should directly mirror the C types//! as closely as possible. Using types like `Box<T>` where the C//! definition is just using `T*` can lead to undefined behavior, as//! described in [rust-lang/unsafe-code-guidelines#198][ucg#198].//!//! # Considerations for unsafe code//!//! **Warning: This section is not normative and is subject to change, possibly//! being relaxed in the future! It is a simplified summary of the rules//! currently implemented in the compiler.**//!//! The aliasing rules for `Box<T>` are the same as for `&mut T`. `Box<T>`//! asserts uniqueness over its content. Using raw pointers derived from a box//! after that box has been mutated through, moved or borrowed as `&mut T`//! is not allowed. For more guidance on working with box from unsafe code, see//! [rust-lang/unsafe-code-guidelines#326][ucg#326].//!//!//! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198//! [ucg#326]: https://github.com/rust-lang/unsafe-code-guidelines/issues/326//! [dereferencing]: core::ops::Deref//! [`Box::<T>::from_raw(value)`]: Box::from_raw//! [`Global`]: crate::alloc::Global//! [`Layout`]: crate::alloc::Layout//! [`Layout::for_value(&*value)`]: crate::alloc::Layout::for_value//! [valid]: ptr#safety #![stable(feature = "rust1", since = "1.0.0")] use core::any::Any;use core::async_iter::AsyncIterator;use core::borrow;use core::cmp::Ordering;use core::convert::{From, TryFrom};use core::error::Error;use core::fmt;use core::future::Future;use core::hash::{Hash, Hasher};#[cfg(not(no_global_oom_handling))]use core::iter::FromIterator;use core::iter::{FusedIterator, Iterator};use core::marker::Tuple;use core::marker::{Destruct, Unpin, Unsize};use core::mem;use core::ops::{    CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Generator, GeneratorState, Receiver,};use core::pin::Pin;use core::ptr::{self, Unique};use core::task::{Context, Poll}; #[cfg(not(no_global_oom_handling))]use crate::alloc::{handle_alloc_error, WriteCloneIntoRaw};use crate::alloc::{AllocError, Allocator, Global, Layout};#[cfg(not(no_global_oom_handling))]use crate::borrow::Cow;use crate::raw_vec::RawVec;#[cfg(not(no_global_oom_handling))]use crate::str::from_boxed_utf8_unchecked;#[cfg(not(no_global_oom_handling))]use crate::string::String;#[cfg(not(no_global_oom_handling))]use crate::vec::Vec; #[cfg(not(no_thin))]#[unstable(feature = "thin_box", issue = "92791")]pub use thin::ThinBox; #[cfg(not(no_thin))]mod thin; /// A pointer type that uniquely owns a heap allocation of type `T`.////// See the [module-level documentation](../../std/boxed/index.html) for more.#[lang = "owned_box"]#[fundamental]#[stable(feature = "rust1", since = "1.0.0")]// The declaration of the `Box` struct must be kept in sync with the// `alloc::alloc::box_free` function or ICEs will happen. See the comment// on `box_free` for more details.pub struct Box<    T: ?Sized,    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,>(Unique<T>, A); impl<T> Box<T> {    /// Allocates memory on the heap and then places `x` into it.    ///    /// This doesn't actually allocate if `T` is zero-sized.    ///    /// # Examples    ///    /// ```    /// let five = Box::new(5);    /// ```    #[cfg(all(not(no_global_oom_handling)))]    #[inline(always)]    #[stable(feature = "rust1", since = "1.0.0")]    #[must_use]    pub fn new(x: T) -> Self {        #[rustc_box]        Box::new(x)    }     /// Constructs a new box with uninitialized contents.    ///    /// # Examples    ///    /// ```    /// #![feature(new_uninit)]    ///    /// let mut five = Box::<u32>::new_uninit();    ///    /// let five = unsafe {    ///     // Deferred initialization:    ///     five.as_mut_ptr().write(5);    ///    ///     five.assume_init()    /// };    ///    /// assert_eq!(*five, 5)    /// ```    #[cfg(not(no_global_oom_handling))]    #[unstable(feature = "new_uninit", issue = "63291")]    #[must_use]    #[inline]    pub fn new_uninit() -> Box<mem::MaybeUninit<T>> {        Self::new_uninit_in(Global)    }     /// Constructs a new `Box` with uninitialized contents, with the memory    /// being filled with `0` bytes.    ///    /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage    /// of this method.    ///    /// # Examples    ///    /// ```    /// #![feature(new_uninit)]    ///    /// let zero = Box::<u32>::new_zeroed();    /// let zero = unsafe { zero.assume_init() };    ///    /// assert_eq!(*zero, 0)    /// ```    ///    /// [zeroed]: mem::MaybeUninit::zeroed    #[cfg(not(no_global_oom_handling))]    #[inline]    #[unstable(feature = "new_uninit", issue = "63291")]    #[must_use]    pub fn new_zeroed() -> Box<mem::MaybeUninit<T>> {        Self::new_zeroed_in(Global)    }     /// Constructs a new `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then    /// `x` will be pinned in memory and unable to be moved.    ///    /// Constructing and pinning of the `Box` can also be done in two steps: `Box::pin(x)`    /// does the same as <code>[Box::into_pin]\([Box::new]\(x))</code>. Consider using    /// [`into_pin`](Box::into_pin) if you already have a `Box<T>`, or if you want to    /// construct a (pinned) `Box` in a different way than with [`Box::new`].    #[cfg(not(no_global_oom_handling))]    #[stable(feature = "pin", since = "1.33.0")]    #[must_use]    #[inline(always)]    pub fn pin(x: T) -> Pin<Box<T>> {        (#[rustc_box]        Box::new(x))        .into()    }     /// Allocates memory on the heap then places `x` into it,    /// returning an error if the allocation fails    ///    /// This doesn't actually allocate if `T` is zero-sized.    ///    /// # Examples    ///    /// ```    /// #![feature(allocator_api)]    ///    /// let five = Box::try_new(5)?;    /// # Ok::<(), std::alloc::AllocError>(())    /// ```    #[unstable(feature = "allocator_api", issue = "32838")]    #[inline]    pub fn try_new(x: T) -> Result<Self, AllocError> {        Self::try_new_in(x, Global)    }     /// Constructs a new box with uninitialized contents on the heap,    /// returning an error if the allocation fails    ///    /// # Examples    ///    /// ```    /// #![feature(allocator_api, new_uninit)]    ///    /// let mut five = Box::<u32>::try_new_uninit()?;    ///    /// let five = unsafe {    ///     // Deferred initialization:    ///     five.as_mut_ptr().write(5);    ///    ///     five.assume_init()    /// };    ///    /// assert_eq!(*five, 5);    /// # Ok::<(), std::alloc::AllocError>(())    /// ```    #[unstable(feature = "allocator_api", issue = "32838")]    // #[unstable(feature = "new_uninit", issue = "63291")]    #[inline]    pub fn try_new_uninit() -> Result<Box<mem::MaybeUninit<T>>, AllocError> {        Box::try_new_uninit_in(Global)    }     /// Constructs a new `Box` with uninitialized contents, with the memory    /// being filled with `0` bytes on the heap    ///    /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage    /// of this method.    ///    /// # Examples    ///    /// ```    /// #![feature(allocator_api, new_uninit)]    ///    /// let zero = Box::<u32>::try_new_zeroed()?;    /// let zero = unsafe { zero.assume_init() };    ///    /// assert_eq!(*zero, 0);    /// # Ok::<(), std::alloc::AllocError>(())    /// ```    ///    /// [zeroed]: mem::MaybeUninit::zeroed    #[unstable(feature = "allocator_api", issue = "32838")]    // #[unstable(feature = "new_uninit", issue = "63291")]    #[inline]    pub fn try_new_zeroed() -> Result<Box<mem::MaybeUninit<T>>, AllocError> {        Box::try_new_zeroed_in(Global)    }} impl<T, A: Allocator> Box<T, A> {    /// Allocates memory in the given allocator then places `x` into it.    ///    /// This doesn't actually allocate if `T` is zero-sized.    ///    /// # Examples    ///    /// ```    /// #![feature(allocator_api)]    ///    /// use std::alloc::System;    ///    /// let five = Box::new_in(5, System);    /// ```    #[cfg(not(no_global_oom_handling))]    #[unstable(feature = "allocator_api", issue = "32838")]    #[rustc_const_unstable(feature = "const_box", issue = "92521")]    #[must_use]    #[inline]    pub const fn new_in(x: T, alloc: A) -> Self    where        A: ~const Allocator + ~const Destruct,    {        let mut boxed = Self::new_uninit_in(alloc);        unsafe {            boxed.as_mut_ptr().write(x);            boxed.assume_init()        }    }     /// Allocates memory in the given allocator then places `x` into it,    /// returning an error if the allocation fails    ///    /// This doesn't actually allocate if `T` is zero-sized.    ///    /// # Examples    ///    /// ```    /// #![feature(allocator_api)]    ///    /// use std::alloc::System;    ///    /// let five = Box::try_new_in(5, System)?;    /// # Ok::<(), std::alloc::AllocError>(())    /// ```    #[unstable(feature = "allocator_api", issue = "32838")]    #[rustc_const_unstable(feature = "const_box", issue = "92521")]    #[inline]    pub const fn try_new_in(x: T, alloc: A) -> Result<Self, AllocError>    where        T: ~const Destruct,        A: ~const Allocator + ~const Destruct,    {        let mut boxed = Self::try_new_uninit_in(alloc)?;        unsafe {            boxed.as_mut_ptr().write(x);            Ok(boxed.assume_init())        }    }     /// Constructs a new box with uninitialized contents in the provided allocator.    ///    /// # Examples    ///    /// ```    /// #![feature(allocator_api, new_uninit)]    ///    /// use std::alloc::System;    ///    /// let mut five = Box::<u32, _>::new_uninit_in(System);    ///    /// let five = unsafe {    ///     // Deferred initialization:    ///     five.as_mut_ptr().write(5);    ///    ///     five.assume_init()    /// };    ///    /// assert_eq!(*five, 5)    /// ```    #[unstable(feature = "allocator_api", issue = "32838")]    #[rustc_const_unstable(feature = "const_box", issue = "92521")]    #[cfg(not(no_global_oom_handling))]    #[must_use]    // #[unstable(feature = "new_uninit", issue = "63291")]    pub const fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A>    where        A: ~const Allocator + ~const Destruct,    {        let layout = Layout::new::<mem::MaybeUninit<T>>();        // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable.        // That would make code size bigger.        match Box::try_new_uninit_in(alloc) {            Ok(m) => m,            Err(_) => handle_alloc_error(layout),        }    }     /// Constructs a new box with uninitialized contents in the provided allocator,    /// returning an error if the allocation fails    ///    /// # Examples    ///    /// ```    /// #![feature(allocator_api, new_uninit)]    ///    /// use std::alloc::System;    ///    /// let mut five = Box::<u32, _>::try_new_uninit_in(System)?;    ///    /// let five = unsafe {    ///     // Deferred initialization:    ///     five.as_mut_ptr().write(5);    ///    ///     five.assume_init()    /// };    ///    /// assert_eq!(*five, 5);    /// # Ok::<(), std::alloc::AllocError>(())    /// ```    #[unstable(feature = "allocator_api", issue = "32838")]    // #[unstable(feature = "new_uninit", issue = "63291")]    #[rustc_const_unstable(feature = "const_box", issue = "92521")]    pub const fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError>    where        A: ~const Allocator + ~const Destruct,    {        let layout = Layout::new::<mem::MaybeUninit<T>>();        let ptr = alloc.allocate(layout)?.cast();        unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }    }     /// Constructs a new `Box` with uninitialized contents, with the memory

Lines 1–500 of 2432.