mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 21:21:41 +00:00
rust: upgrade to Rust 1.68.2
This is the first upgrade to the Rust toolchain since the initial Rust
merge, from 1.62.0 to 1.68.2 (i.e. the latest).
# Context
The kernel currently supports only a single Rust version [1] (rather
than a minimum) given our usage of some "unstable" Rust features [2]
which do not promise backwards compatibility.
The goal is to reach a point where we can declare a minimum version for
the toolchain. For instance, by waiting for some of the features to be
stabilized. Therefore, the first minimum Rust version that the kernel
will support is "in the future".
# Upgrade policy
Given we will eventually need to reach that minimum version, it would be
ideal to upgrade the compiler from time to time to be as close as
possible to that goal and find any issues sooner. In the extreme, we
could upgrade as soon as a new Rust release is out. Of course, upgrading
so often is in stark contrast to what one normally would need for GCC
and LLVM, especially given the release schedule: 6 weeks for Rust vs.
half a year for LLVM and a year for GCC.
Having said that, there is no particular advantage to updating slowly
either: kernel developers in "stable" distributions are unlikely to be
able to use their distribution-provided Rust toolchain for the kernel
anyway [3]. Instead, by routinely upgrading to the latest instead,
kernel developers using Linux distributions that track the latest Rust
release may be able to use those rather than Rust-provided ones,
especially if their package manager allows to pin / hold back /
downgrade the version for some days during windows where the version may
not match. For instance, Arch, Fedora, Gentoo and openSUSE all provide
and track the latest version of Rust as they get released every 6 weeks.
Then, when the minimum version is reached, we will stop upgrading and
decide how wide the window of support will be. For instance, a year of
Rust versions. We will probably want to start small, and then widen it
over time, just like the kernel did originally for LLVM, see commit
3519c4d6e0
("Documentation: add minimum clang/llvm version").
# Unstable features stabilized
This upgrade allows us to remove the following unstable features since
they were stabilized:
- `feature(explicit_generic_args_with_impl_trait)` (1.63).
- `feature(core_ffi_c)` (1.64).
- `feature(generic_associated_types)` (1.65).
- `feature(const_ptr_offset_from)` (1.65, *).
- `feature(bench_black_box)` (1.66, *).
- `feature(pin_macro)` (1.68).
The ones marked with `*` apply only to our old `rust` branch, not
mainline yet, i.e. only for code that we may potentially upstream.
With this patch applied, the only unstable feature allowed to be used
outside the `kernel` crate is `new_uninit`, though other code to be
upstreamed may increase the list.
Please see [2] for details.
# Other required changes
Since 1.63, `rustdoc` triggers the `broken_intra_doc_links` lint for
links pointing to exported (`#[macro_export]`) `macro_rules`. An issue
was opened upstream [4], but it turns out it is intended behavior. For
the moment, just add an explicit reference for each link. Later we can
revisit this if `rustdoc` removes the compatibility measure.
Nevertheless, this was helpful to discover a link that was pointing to
the wrong place unintentionally. Since that one was actually wrong, it
is fixed in a previous commit independently.
Another change was the addition of `cfg(no_rc)` and `cfg(no_sync)` in
upstream [5], thus remove our original changes for that.
Similarly, upstream now tests that it compiles successfully with
`#[cfg(not(no_global_oom_handling))]` [6], which allow us to get rid
of some changes, such as an `#[allow(dead_code)]`.
In addition, remove another `#[allow(dead_code)]` due to new uses
within the standard library.
Finally, add `try_extend_trusted` and move the code in `spec_extend.rs`
since upstream moved it for the infallible version.
# `alloc` upgrade and reviewing
There are a large amount of changes, but the vast majority of them are
due to our `alloc` fork being upgraded at once.
There are two kinds of changes to be aware of: the ones coming from
upstream, which we should follow as closely as possible, and the updates
needed in our added fallible APIs to keep them matching the newer
infallible APIs coming from upstream.
Instead of taking a look at the diff of this patch, an alternative
approach is reviewing a diff of the changes between upstream `alloc` and
the kernel's. This allows to easily inspect the kernel additions only,
especially to check if the fallible methods we already have still match
the infallible ones in the new version coming from upstream.
Another approach is reviewing the changes introduced in the additions in
the kernel fork between the two versions. This is useful to spot
potentially unintended changes to our additions.
To apply these approaches, one may follow steps similar to the following
to generate a pair of patches that show the differences between upstream
Rust and the kernel (for the subset of `alloc` we use) before and after
applying this patch:
# Get the difference with respect to the old version.
git -C rust checkout $(linux/scripts/min-tool-version.sh rustc)
git -C linux ls-tree -r --name-only HEAD -- rust/alloc |
cut -d/ -f3- |
grep -Fv README.md |
xargs -IPATH cp rust/library/alloc/src/PATH linux/rust/alloc/PATH
git -C linux diff --patch-with-stat --summary -R > old.patch
git -C linux restore rust/alloc
# Apply this patch.
git -C linux am rust-upgrade.patch
# Get the difference with respect to the new version.
git -C rust checkout $(linux/scripts/min-tool-version.sh rustc)
git -C linux ls-tree -r --name-only HEAD -- rust/alloc |
cut -d/ -f3- |
grep -Fv README.md |
xargs -IPATH cp rust/library/alloc/src/PATH linux/rust/alloc/PATH
git -C linux diff --patch-with-stat --summary -R > new.patch
git -C linux restore rust/alloc
Now one may check the `new.patch` to take a look at the additions (first
approach) or at the difference between those two patches (second
approach). For the latter, a side-by-side tool is recommended.
Link: https://rust-for-linux.com/rust-version-policy [1]
Link: https://github.com/Rust-for-Linux/linux/issues/2 [2]
Link: https://lore.kernel.org/rust-for-linux/CANiq72mT3bVDKdHgaea-6WiZazd8Mvurqmqegbe5JZxVyLR8Yg@mail.gmail.com/ [3]
Link: https://github.com/rust-lang/rust/issues/106142 [4]
Link: https://github.com/rust-lang/rust/pull/89891 [5]
Link: https://github.com/rust-lang/rust/pull/98652 [6]
Reviewed-by: Björn Roy Baron <bjorn3_gh@protonmail.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-By: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
Tested-by: Ariel Miculas <amiculas@cisco.com>
Tested-by: David Gow <davidgow@google.com>
Tested-by: Boqun Feng <boqun.feng@gmail.com>
Link: https://lore.kernel.org/r/20230418214347.324156-4-ojeda@kernel.org
[ Removed `feature(core_ffi_c)` from `uapi` ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
parent
eed7a146b8
commit
3ed03f4da0
@ -31,7 +31,7 @@ you probably needn't concern yourself with pcmciautils.
|
|||||||
====================== =============== ========================================
|
====================== =============== ========================================
|
||||||
GNU C 5.1 gcc --version
|
GNU C 5.1 gcc --version
|
||||||
Clang/LLVM (optional) 11.0.0 clang --version
|
Clang/LLVM (optional) 11.0.0 clang --version
|
||||||
Rust (optional) 1.62.0 rustc --version
|
Rust (optional) 1.68.2 rustc --version
|
||||||
bindgen (optional) 0.56.0 bindgen --version
|
bindgen (optional) 0.56.0 bindgen --version
|
||||||
GNU make 3.82 make --version
|
GNU make 3.82 make --version
|
||||||
bash 4.2 bash --version
|
bash 4.2 bash --version
|
||||||
|
@ -22,21 +22,24 @@ use core::marker::Destruct;
|
|||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
extern "Rust" {
|
extern "Rust" {
|
||||||
// These are the magic symbols to call the global allocator. rustc generates
|
// These are the magic symbols to call the global allocator. rustc generates
|
||||||
// them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
|
// them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
|
||||||
// (the code expanding that attribute macro generates those functions), or to call
|
// (the code expanding that attribute macro generates those functions), or to call
|
||||||
// the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
|
// the default implementations in std (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
|
||||||
// otherwise.
|
// otherwise.
|
||||||
// The rustc fork of LLVM also special-cases these function names to be able to optimize them
|
// The rustc fork of LLVM 14 and earlier also special-cases these function names to be able to optimize them
|
||||||
// like `malloc`, `realloc`, and `free`, respectively.
|
// like `malloc`, `realloc`, and `free`, respectively.
|
||||||
#[rustc_allocator]
|
#[rustc_allocator]
|
||||||
#[rustc_allocator_nounwind]
|
#[rustc_nounwind]
|
||||||
fn __rust_alloc(size: usize, align: usize) -> *mut u8;
|
fn __rust_alloc(size: usize, align: usize) -> *mut u8;
|
||||||
#[rustc_allocator_nounwind]
|
#[rustc_deallocator]
|
||||||
|
#[rustc_nounwind]
|
||||||
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
|
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
|
||||||
#[rustc_allocator_nounwind]
|
#[rustc_reallocator]
|
||||||
|
#[rustc_nounwind]
|
||||||
fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8;
|
fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8;
|
||||||
#[rustc_allocator_nounwind]
|
#[rustc_allocator_zeroed]
|
||||||
|
#[rustc_nounwind]
|
||||||
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
|
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,11 +75,14 @@ pub use std::alloc::Global;
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::alloc::{alloc, dealloc, Layout};
|
/// use std::alloc::{alloc, dealloc, handle_alloc_error, Layout};
|
||||||
///
|
///
|
||||||
/// unsafe {
|
/// unsafe {
|
||||||
/// let layout = Layout::new::<u16>();
|
/// let layout = Layout::new::<u16>();
|
||||||
/// let ptr = alloc(layout);
|
/// let ptr = alloc(layout);
|
||||||
|
/// if ptr.is_null() {
|
||||||
|
/// handle_alloc_error(layout);
|
||||||
|
/// }
|
||||||
///
|
///
|
||||||
/// *(ptr as *mut u16) = 42;
|
/// *(ptr as *mut u16) = 42;
|
||||||
/// assert_eq!(*(ptr as *mut u16), 42);
|
/// assert_eq!(*(ptr as *mut u16), 42);
|
||||||
@ -349,7 +355,7 @@ pub(crate) const unsafe fn box_free<T: ?Sized, A: ~const Allocator + ~const Dest
|
|||||||
|
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
extern "Rust" {
|
extern "Rust" {
|
||||||
// This is the magic symbol to call the global alloc error handler. rustc generates
|
// This is the magic symbol to call the global alloc error handler. rustc generates
|
||||||
// it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
|
// it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
|
||||||
// default implementations below (`__rdl_oom`) otherwise.
|
// default implementations below (`__rdl_oom`) otherwise.
|
||||||
fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
|
fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
|
||||||
@ -394,25 +400,24 @@ pub use std::alloc::handle_alloc_error;
|
|||||||
#[allow(unused_attributes)]
|
#[allow(unused_attributes)]
|
||||||
#[unstable(feature = "alloc_internals", issue = "none")]
|
#[unstable(feature = "alloc_internals", issue = "none")]
|
||||||
pub mod __alloc_error_handler {
|
pub mod __alloc_error_handler {
|
||||||
use crate::alloc::Layout;
|
// called via generated `__rust_alloc_error_handler` if there is no
|
||||||
|
// `#[alloc_error_handler]`.
|
||||||
// called via generated `__rust_alloc_error_handler`
|
|
||||||
|
|
||||||
// if there is no `#[alloc_error_handler]`
|
|
||||||
#[rustc_std_internal_symbol]
|
#[rustc_std_internal_symbol]
|
||||||
pub unsafe extern "C-unwind" fn __rdl_oom(size: usize, _align: usize) -> ! {
|
pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
|
||||||
panic!("memory allocation of {size} bytes failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// if there is an `#[alloc_error_handler]`
|
|
||||||
#[rustc_std_internal_symbol]
|
|
||||||
pub unsafe extern "C-unwind" fn __rg_oom(size: usize, align: usize) -> ! {
|
|
||||||
let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
|
|
||||||
extern "Rust" {
|
extern "Rust" {
|
||||||
#[lang = "oom"]
|
// This symbol is emitted by rustc next to __rust_alloc_error_handler.
|
||||||
fn oom_impl(layout: Layout) -> !;
|
// Its value depends on the -Zoom={panic,abort} compiler option.
|
||||||
|
static __rust_alloc_error_handler_should_panic: u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_unsafe)]
|
||||||
|
if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
|
||||||
|
panic!("memory allocation of {size} bytes failed")
|
||||||
|
} else {
|
||||||
|
core::panicking::panic_nounwind_fmt(format_args!(
|
||||||
|
"memory allocation of {size} bytes failed"
|
||||||
|
))
|
||||||
}
|
}
|
||||||
unsafe { oom_impl(layout) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
|
||||||
//! A pointer type for heap allocation.
|
//! The `Box<T>` type for heap allocation.
|
||||||
//!
|
//!
|
||||||
//! [`Box<T>`], casually referred to as a 'box', provides the simplest form of
|
//! [`Box<T>`], casually referred to as a 'box', provides the simplest form of
|
||||||
//! heap allocation in Rust. Boxes provide ownership for this allocation, and
|
//! heap allocation in Rust. Boxes provide ownership for this allocation, and
|
||||||
@ -124,7 +124,21 @@
|
|||||||
//! definition is just using `T*` can lead to undefined behavior, as
|
//! definition is just using `T*` can lead to undefined behavior, as
|
||||||
//! described in [rust-lang/unsafe-code-guidelines#198][ucg#198].
|
//! 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#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
|
//! [dereferencing]: core::ops::Deref
|
||||||
//! [`Box::<T>::from_raw(value)`]: Box::from_raw
|
//! [`Box::<T>::from_raw(value)`]: Box::from_raw
|
||||||
//! [`Global`]: crate::alloc::Global
|
//! [`Global`]: crate::alloc::Global
|
||||||
@ -139,12 +153,14 @@ use core::async_iter::AsyncIterator;
|
|||||||
use core::borrow;
|
use core::borrow;
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
use core::convert::{From, TryFrom};
|
use core::convert::{From, TryFrom};
|
||||||
|
use core::error::Error;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
use core::hash::{Hash, Hasher};
|
use core::hash::{Hash, Hasher};
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
use core::iter::FromIterator;
|
use core::iter::FromIterator;
|
||||||
use core::iter::{FusedIterator, Iterator};
|
use core::iter::{FusedIterator, Iterator};
|
||||||
|
use core::marker::Tuple;
|
||||||
use core::marker::{Destruct, Unpin, Unsize};
|
use core::marker::{Destruct, Unpin, Unsize};
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::ops::{
|
use core::ops::{
|
||||||
@ -163,6 +179,8 @@ use crate::raw_vec::RawVec;
|
|||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
use crate::str::from_boxed_utf8_unchecked;
|
use crate::str::from_boxed_utf8_unchecked;
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
use crate::string::String;
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
use crate::vec::Vec;
|
use crate::vec::Vec;
|
||||||
|
|
||||||
#[cfg(not(no_thin))]
|
#[cfg(not(no_thin))]
|
||||||
@ -172,7 +190,7 @@ pub use thin::ThinBox;
|
|||||||
#[cfg(not(no_thin))]
|
#[cfg(not(no_thin))]
|
||||||
mod thin;
|
mod thin;
|
||||||
|
|
||||||
/// A pointer type for heap allocation.
|
/// A pointer type that uniquely owns a heap allocation of type `T`.
|
||||||
///
|
///
|
||||||
/// See the [module-level documentation](../../std/boxed/index.html) for more.
|
/// See the [module-level documentation](../../std/boxed/index.html) for more.
|
||||||
#[lang = "owned_box"]
|
#[lang = "owned_box"]
|
||||||
@ -196,12 +214,13 @@ impl<T> Box<T> {
|
|||||||
/// ```
|
/// ```
|
||||||
/// let five = Box::new(5);
|
/// let five = Box::new(5);
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(all(not(no_global_oom_handling)))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new(x: T) -> Self {
|
pub fn new(x: T) -> Self {
|
||||||
box x
|
#[rustc_box]
|
||||||
|
Box::new(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new box with uninitialized contents.
|
/// Constructs a new box with uninitialized contents.
|
||||||
@ -256,14 +275,21 @@ impl<T> Box<T> {
|
|||||||
Self::new_zeroed_in(Global)
|
Self::new_zeroed_in(Global)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new `Pin<Box<T>>`. If `T` does not implement `Unpin`, then
|
/// Constructs a new `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
|
||||||
/// `x` will be pinned in memory and unable to be moved.
|
/// `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))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
#[stable(feature = "pin", since = "1.33.0")]
|
#[stable(feature = "pin", since = "1.33.0")]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn pin(x: T) -> Pin<Box<T>> {
|
pub fn pin(x: T) -> Pin<Box<T>> {
|
||||||
(box x).into()
|
(#[rustc_box]
|
||||||
|
Box::new(x))
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocates memory on the heap then places `x` into it,
|
/// Allocates memory on the heap then places `x` into it,
|
||||||
@ -543,8 +569,13 @@ impl<T, A: Allocator> Box<T, A> {
|
|||||||
unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
|
unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new `Pin<Box<T, A>>`. If `T` does not implement `Unpin`, then
|
/// Constructs a new `Pin<Box<T, A>>`. If `T` does not implement [`Unpin`], then
|
||||||
/// `x` will be pinned in memory and unable to be moved.
|
/// `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_in(x, alloc)`
|
||||||
|
/// does the same as <code>[Box::into_pin]\([Box::new_in]\(x, alloc))</code>. Consider using
|
||||||
|
/// [`into_pin`](Box::into_pin) if you already have a `Box<T, A>`, or if you want to
|
||||||
|
/// construct a (pinned) `Box` in a different way than with [`Box::new_in`].
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
|
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
|
||||||
@ -926,6 +957,7 @@ impl<T: ?Sized> Box<T> {
|
|||||||
/// [`Layout`]: crate::Layout
|
/// [`Layout`]: crate::Layout
|
||||||
#[stable(feature = "box_raw", since = "1.4.0")]
|
#[stable(feature = "box_raw", since = "1.4.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[must_use = "call `drop(Box::from_raw(ptr))` if you intend to drop the `Box`"]
|
||||||
pub unsafe fn from_raw(raw: *mut T) -> Self {
|
pub unsafe fn from_raw(raw: *mut T) -> Self {
|
||||||
unsafe { Self::from_raw_in(raw, Global) }
|
unsafe { Self::from_raw_in(raw, Global) }
|
||||||
}
|
}
|
||||||
@ -1160,19 +1192,44 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
|
|||||||
unsafe { &mut *mem::ManuallyDrop::new(b).0.as_ptr() }
|
unsafe { &mut *mem::ManuallyDrop::new(b).0.as_ptr() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts a `Box<T>` into a `Pin<Box<T>>`
|
/// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
|
||||||
|
/// `*boxed` will be pinned in memory and unable to be moved.
|
||||||
///
|
///
|
||||||
/// This conversion does not allocate on the heap and happens in place.
|
/// This conversion does not allocate on the heap and happens in place.
|
||||||
///
|
///
|
||||||
/// This is also available via [`From`].
|
/// This is also available via [`From`].
|
||||||
#[unstable(feature = "box_into_pin", issue = "62370")]
|
///
|
||||||
|
/// Constructing and pinning a `Box` with <code>Box::into_pin([Box::new]\(x))</code>
|
||||||
|
/// can also be written more concisely using <code>[Box::pin]\(x)</code>.
|
||||||
|
/// This `into_pin` method is useful if you already have a `Box<T>`, or you are
|
||||||
|
/// constructing a (pinned) `Box` in a different way than with [`Box::new`].
|
||||||
|
///
|
||||||
|
/// # Notes
|
||||||
|
///
|
||||||
|
/// It's not recommended that crates add an impl like `From<Box<T>> for Pin<T>`,
|
||||||
|
/// as it'll introduce an ambiguity when calling `Pin::from`.
|
||||||
|
/// A demonstration of such a poor impl is shown below.
|
||||||
|
///
|
||||||
|
/// ```compile_fail
|
||||||
|
/// # use std::pin::Pin;
|
||||||
|
/// struct Foo; // A type defined in this crate.
|
||||||
|
/// impl From<Box<()>> for Pin<Foo> {
|
||||||
|
/// fn from(_: Box<()>) -> Pin<Foo> {
|
||||||
|
/// Pin::new(Foo)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let foo = Box::new(());
|
||||||
|
/// let bar = Pin::from(foo);
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "box_into_pin", since = "1.63.0")]
|
||||||
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
|
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
|
||||||
pub const fn into_pin(boxed: Self) -> Pin<Self>
|
pub const fn into_pin(boxed: Self) -> Pin<Self>
|
||||||
where
|
where
|
||||||
A: 'static,
|
A: 'static,
|
||||||
{
|
{
|
||||||
// It's not possible to move or replace the insides of a `Pin<Box<T>>`
|
// It's not possible to move or replace the insides of a `Pin<Box<T>>`
|
||||||
// when `T: !Unpin`, so it's safe to pin it directly without any
|
// when `T: !Unpin`, so it's safe to pin it directly without any
|
||||||
// additional requirements.
|
// additional requirements.
|
||||||
unsafe { Pin::new_unchecked(boxed) }
|
unsafe { Pin::new_unchecked(boxed) }
|
||||||
}
|
}
|
||||||
@ -1190,7 +1247,8 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
|
|||||||
impl<T: Default> Default for Box<T> {
|
impl<T: Default> Default for Box<T> {
|
||||||
/// Creates a `Box<T>`, with the `Default` value for T.
|
/// Creates a `Box<T>`, with the `Default` value for T.
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
box T::default()
|
#[rustc_box]
|
||||||
|
Box::new(T::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1408,9 +1466,17 @@ impl<T: ?Sized, A: Allocator> const From<Box<T, A>> for Pin<Box<T, A>>
|
|||||||
where
|
where
|
||||||
A: 'static,
|
A: 'static,
|
||||||
{
|
{
|
||||||
/// Converts a `Box<T>` into a `Pin<Box<T>>`
|
/// Converts a `Box<T>` into a `Pin<Box<T>>`. If `T` does not implement [`Unpin`], then
|
||||||
|
/// `*boxed` will be pinned in memory and unable to be moved.
|
||||||
///
|
///
|
||||||
/// This conversion does not allocate on the heap and happens in place.
|
/// This conversion does not allocate on the heap and happens in place.
|
||||||
|
///
|
||||||
|
/// This is also available via [`Box::into_pin`].
|
||||||
|
///
|
||||||
|
/// Constructing and pinning a `Box` with <code><Pin<Box\<T>>>::from([Box::new]\(x))</code>
|
||||||
|
/// can also be written more concisely using <code>[Box::pin]\(x)</code>.
|
||||||
|
/// This `From` implementation is useful if you already have a `Box<T>`, or you are
|
||||||
|
/// constructing a (pinned) `Box` in a different way than with [`Box::new`].
|
||||||
fn from(boxed: Box<T, A>) -> Self {
|
fn from(boxed: Box<T, A>) -> Self {
|
||||||
Box::into_pin(boxed)
|
Box::into_pin(boxed)
|
||||||
}
|
}
|
||||||
@ -1422,7 +1488,7 @@ impl<T: Copy> From<&[T]> for Box<[T]> {
|
|||||||
/// Converts a `&[T]` into a `Box<[T]>`
|
/// Converts a `&[T]` into a `Box<[T]>`
|
||||||
///
|
///
|
||||||
/// This conversion allocates on the heap
|
/// This conversion allocates on the heap
|
||||||
/// and performs a copy of `slice`.
|
/// and performs a copy of `slice` and its contents.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
/// ```rust
|
/// ```rust
|
||||||
@ -1554,10 +1620,27 @@ impl<T, const N: usize> From<[T; N]> for Box<[T]> {
|
|||||||
/// println!("{boxed:?}");
|
/// println!("{boxed:?}");
|
||||||
/// ```
|
/// ```
|
||||||
fn from(array: [T; N]) -> Box<[T]> {
|
fn from(array: [T; N]) -> Box<[T]> {
|
||||||
box array
|
#[rustc_box]
|
||||||
|
Box::new(array)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Casts a boxed slice to a boxed array.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// `boxed_slice.len()` must be exactly `N`.
|
||||||
|
unsafe fn boxed_slice_as_array_unchecked<T, A: Allocator, const N: usize>(
|
||||||
|
boxed_slice: Box<[T], A>,
|
||||||
|
) -> Box<[T; N], A> {
|
||||||
|
debug_assert_eq!(boxed_slice.len(), N);
|
||||||
|
|
||||||
|
let (ptr, alloc) = Box::into_raw_with_allocator(boxed_slice);
|
||||||
|
// SAFETY: Pointer and allocator came from an existing box,
|
||||||
|
// and our safety condition requires that the length is exactly `N`
|
||||||
|
unsafe { Box::from_raw_in(ptr as *mut [T; N], alloc) }
|
||||||
|
}
|
||||||
|
|
||||||
#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
|
#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
|
||||||
impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
|
impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
|
||||||
type Error = Box<[T]>;
|
type Error = Box<[T]>;
|
||||||
@ -1573,13 +1656,46 @@ impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
|
|||||||
/// `boxed_slice.len()` does not equal `N`.
|
/// `boxed_slice.len()` does not equal `N`.
|
||||||
fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> {
|
fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> {
|
||||||
if boxed_slice.len() == N {
|
if boxed_slice.len() == N {
|
||||||
Ok(unsafe { Box::from_raw(Box::into_raw(boxed_slice) as *mut [T; N]) })
|
Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
|
||||||
} else {
|
} else {
|
||||||
Err(boxed_slice)
|
Err(boxed_slice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
#[stable(feature = "boxed_array_try_from_vec", since = "1.66.0")]
|
||||||
|
impl<T, const N: usize> TryFrom<Vec<T>> for Box<[T; N]> {
|
||||||
|
type Error = Vec<T>;
|
||||||
|
|
||||||
|
/// Attempts to convert a `Vec<T>` into a `Box<[T; N]>`.
|
||||||
|
///
|
||||||
|
/// Like [`Vec::into_boxed_slice`], this is in-place if `vec.capacity() == N`,
|
||||||
|
/// but will require a reallocation otherwise.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns the original `Vec<T>` in the `Err` variant if
|
||||||
|
/// `boxed_slice.len()` does not equal `N`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// This can be used with [`vec!`] to create an array on the heap:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let state: Box<[f32; 100]> = vec![1.0; 100].try_into().unwrap();
|
||||||
|
/// assert_eq!(state.len(), 100);
|
||||||
|
/// ```
|
||||||
|
fn try_from(vec: Vec<T>) -> Result<Self, Self::Error> {
|
||||||
|
if vec.len() == N {
|
||||||
|
let boxed_slice = vec.into_boxed_slice();
|
||||||
|
Ok(unsafe { boxed_slice_as_array_unchecked(boxed_slice) })
|
||||||
|
} else {
|
||||||
|
Err(vec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<A: Allocator> Box<dyn Any, A> {
|
impl<A: Allocator> Box<dyn Any, A> {
|
||||||
/// Attempt to downcast the box to a concrete type.
|
/// Attempt to downcast the box to a concrete type.
|
||||||
///
|
///
|
||||||
@ -1869,7 +1985,7 @@ impl<I: ExactSizeIterator + ?Sized, A: Allocator> ExactSizeIterator for Box<I, A
|
|||||||
impl<I: FusedIterator + ?Sized, A: Allocator> FusedIterator for Box<I, A> {}
|
impl<I: FusedIterator + ?Sized, A: Allocator> FusedIterator for Box<I, A> {}
|
||||||
|
|
||||||
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
|
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
|
||||||
impl<Args, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
|
impl<Args: Tuple, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
|
||||||
type Output = <F as FnOnce<Args>>::Output;
|
type Output = <F as FnOnce<Args>>::Output;
|
||||||
|
|
||||||
extern "rust-call" fn call_once(self, args: Args) -> Self::Output {
|
extern "rust-call" fn call_once(self, args: Args) -> Self::Output {
|
||||||
@ -1878,20 +1994,20 @@ impl<Args, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
|
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
|
||||||
impl<Args, F: FnMut<Args> + ?Sized, A: Allocator> FnMut<Args> for Box<F, A> {
|
impl<Args: Tuple, F: FnMut<Args> + ?Sized, A: Allocator> FnMut<Args> for Box<F, A> {
|
||||||
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
|
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
|
||||||
<F as FnMut<Args>>::call_mut(self, args)
|
<F as FnMut<Args>>::call_mut(self, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
|
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
|
||||||
impl<Args, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> {
|
impl<Args: Tuple, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> {
|
||||||
extern "rust-call" fn call(&self, args: Args) -> Self::Output {
|
extern "rust-call" fn call(&self, args: Args) -> Self::Output {
|
||||||
<F as Fn<Args>>::call(self, args)
|
<F as Fn<Args>>::call(self, args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "coerce_unsized", issue = "27732")]
|
#[unstable(feature = "coerce_unsized", issue = "18598")]
|
||||||
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
|
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
|
||||||
|
|
||||||
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
|
#[unstable(feature = "dispatch_from_dyn", issue = "none")]
|
||||||
@ -1973,8 +2089,7 @@ impl<T: ?Sized, A: Allocator> AsMut<T> for Box<T, A> {
|
|||||||
* could have a method to project a Pin<T> from it.
|
* could have a method to project a Pin<T> from it.
|
||||||
*/
|
*/
|
||||||
#[stable(feature = "pin", since = "1.33.0")]
|
#[stable(feature = "pin", since = "1.33.0")]
|
||||||
#[rustc_const_unstable(feature = "const_box", issue = "92521")]
|
impl<T: ?Sized, A: Allocator> Unpin for Box<T, A> where A: 'static {}
|
||||||
impl<T: ?Sized, A: Allocator> const Unpin for Box<T, A> where A: 'static {}
|
|
||||||
|
|
||||||
#[unstable(feature = "generator_trait", issue = "43122")]
|
#[unstable(feature = "generator_trait", issue = "43122")]
|
||||||
impl<G: ?Sized + Generator<R> + Unpin, R, A: Allocator> Generator<R> for Box<G, A>
|
impl<G: ?Sized + Generator<R> + Unpin, R, A: Allocator> Generator<R> for Box<G, A>
|
||||||
@ -2026,3 +2141,292 @@ impl<S: ?Sized + AsyncIterator + Unpin> AsyncIterator for Box<S> {
|
|||||||
(**self).size_hint()
|
(**self).size_hint()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl dyn Error {
|
||||||
|
#[inline]
|
||||||
|
#[stable(feature = "error_downcast", since = "1.3.0")]
|
||||||
|
#[rustc_allow_incoherent_impl]
|
||||||
|
/// Attempts to downcast the box to a concrete type.
|
||||||
|
pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error>> {
|
||||||
|
if self.is::<T>() {
|
||||||
|
unsafe {
|
||||||
|
let raw: *mut dyn Error = Box::into_raw(self);
|
||||||
|
Ok(Box::from_raw(raw as *mut T))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl dyn Error + Send {
|
||||||
|
#[inline]
|
||||||
|
#[stable(feature = "error_downcast", since = "1.3.0")]
|
||||||
|
#[rustc_allow_incoherent_impl]
|
||||||
|
/// Attempts to downcast the box to a concrete type.
|
||||||
|
pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<dyn Error + Send>> {
|
||||||
|
let err: Box<dyn Error> = self;
|
||||||
|
<dyn Error>::downcast(err).map_err(|s| unsafe {
|
||||||
|
// Reapply the `Send` marker.
|
||||||
|
mem::transmute::<Box<dyn Error>, Box<dyn Error + Send>>(s)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl dyn Error + Send + Sync {
|
||||||
|
#[inline]
|
||||||
|
#[stable(feature = "error_downcast", since = "1.3.0")]
|
||||||
|
#[rustc_allow_incoherent_impl]
|
||||||
|
/// Attempts to downcast the box to a concrete type.
|
||||||
|
pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
|
||||||
|
let err: Box<dyn Error> = self;
|
||||||
|
<dyn Error>::downcast(err).map_err(|s| unsafe {
|
||||||
|
// Reapply the `Send + Sync` marker.
|
||||||
|
mem::transmute::<Box<dyn Error>, Box<dyn Error + Send + Sync>>(s)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl<'a, E: Error + 'a> From<E> for Box<dyn Error + 'a> {
|
||||||
|
/// Converts a type of [`Error`] into a box of dyn [`Error`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::error::Error;
|
||||||
|
/// use std::fmt;
|
||||||
|
/// use std::mem;
|
||||||
|
///
|
||||||
|
/// #[derive(Debug)]
|
||||||
|
/// struct AnError;
|
||||||
|
///
|
||||||
|
/// impl fmt::Display for AnError {
|
||||||
|
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
/// write!(f, "An error")
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl Error for AnError {}
|
||||||
|
///
|
||||||
|
/// let an_error = AnError;
|
||||||
|
/// assert!(0 == mem::size_of_val(&an_error));
|
||||||
|
/// let a_boxed_error = Box::<dyn Error>::from(an_error);
|
||||||
|
/// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
|
||||||
|
/// ```
|
||||||
|
fn from(err: E) -> Box<dyn Error + 'a> {
|
||||||
|
Box::new(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl<'a, E: Error + Send + Sync + 'a> From<E> for Box<dyn Error + Send + Sync + 'a> {
|
||||||
|
/// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of
|
||||||
|
/// dyn [`Error`] + [`Send`] + [`Sync`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::error::Error;
|
||||||
|
/// use std::fmt;
|
||||||
|
/// use std::mem;
|
||||||
|
///
|
||||||
|
/// #[derive(Debug)]
|
||||||
|
/// struct AnError;
|
||||||
|
///
|
||||||
|
/// impl fmt::Display for AnError {
|
||||||
|
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
/// write!(f, "An error")
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// impl Error for AnError {}
|
||||||
|
///
|
||||||
|
/// unsafe impl Send for AnError {}
|
||||||
|
///
|
||||||
|
/// unsafe impl Sync for AnError {}
|
||||||
|
///
|
||||||
|
/// let an_error = AnError;
|
||||||
|
/// assert!(0 == mem::size_of_val(&an_error));
|
||||||
|
/// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(an_error);
|
||||||
|
/// assert!(
|
||||||
|
/// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
|
||||||
|
/// ```
|
||||||
|
fn from(err: E) -> Box<dyn Error + Send + Sync + 'a> {
|
||||||
|
Box::new(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl From<String> for Box<dyn Error + Send + Sync> {
|
||||||
|
/// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::error::Error;
|
||||||
|
/// use std::mem;
|
||||||
|
///
|
||||||
|
/// let a_string_error = "a string error".to_string();
|
||||||
|
/// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_string_error);
|
||||||
|
/// assert!(
|
||||||
|
/// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
fn from(err: String) -> Box<dyn Error + Send + Sync> {
|
||||||
|
struct StringError(String);
|
||||||
|
|
||||||
|
impl Error for StringError {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for StringError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purposefully skip printing "StringError(..)"
|
||||||
|
impl fmt::Debug for StringError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Debug::fmt(&self.0, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Box::new(StringError(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
#[stable(feature = "string_box_error", since = "1.6.0")]
|
||||||
|
impl From<String> for Box<dyn Error> {
|
||||||
|
/// Converts a [`String`] into a box of dyn [`Error`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::error::Error;
|
||||||
|
/// use std::mem;
|
||||||
|
///
|
||||||
|
/// let a_string_error = "a string error".to_string();
|
||||||
|
/// let a_boxed_error = Box::<dyn Error>::from(a_string_error);
|
||||||
|
/// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
|
||||||
|
/// ```
|
||||||
|
fn from(str_err: String) -> Box<dyn Error> {
|
||||||
|
let err1: Box<dyn Error + Send + Sync> = From::from(str_err);
|
||||||
|
let err2: Box<dyn Error> = err1;
|
||||||
|
err2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl<'a> From<&str> for Box<dyn Error + Send + Sync + 'a> {
|
||||||
|
/// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
|
||||||
|
///
|
||||||
|
/// [`str`]: prim@str
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::error::Error;
|
||||||
|
/// use std::mem;
|
||||||
|
///
|
||||||
|
/// let a_str_error = "a str error";
|
||||||
|
/// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_str_error);
|
||||||
|
/// assert!(
|
||||||
|
/// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
fn from(err: &str) -> Box<dyn Error + Send + Sync + 'a> {
|
||||||
|
From::from(String::from(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
#[stable(feature = "string_box_error", since = "1.6.0")]
|
||||||
|
impl From<&str> for Box<dyn Error> {
|
||||||
|
/// Converts a [`str`] into a box of dyn [`Error`].
|
||||||
|
///
|
||||||
|
/// [`str`]: prim@str
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::error::Error;
|
||||||
|
/// use std::mem;
|
||||||
|
///
|
||||||
|
/// let a_str_error = "a str error";
|
||||||
|
/// let a_boxed_error = Box::<dyn Error>::from(a_str_error);
|
||||||
|
/// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
|
||||||
|
/// ```
|
||||||
|
fn from(err: &str) -> Box<dyn Error> {
|
||||||
|
From::from(String::from(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
#[stable(feature = "cow_box_error", since = "1.22.0")]
|
||||||
|
impl<'a, 'b> From<Cow<'b, str>> for Box<dyn Error + Send + Sync + 'a> {
|
||||||
|
/// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::error::Error;
|
||||||
|
/// use std::mem;
|
||||||
|
/// use std::borrow::Cow;
|
||||||
|
///
|
||||||
|
/// let a_cow_str_error = Cow::from("a str error");
|
||||||
|
/// let a_boxed_error = Box::<dyn Error + Send + Sync>::from(a_cow_str_error);
|
||||||
|
/// assert!(
|
||||||
|
/// mem::size_of::<Box<dyn Error + Send + Sync>>() == mem::size_of_val(&a_boxed_error))
|
||||||
|
/// ```
|
||||||
|
fn from(err: Cow<'b, str>) -> Box<dyn Error + Send + Sync + 'a> {
|
||||||
|
From::from(String::from(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
#[stable(feature = "cow_box_error", since = "1.22.0")]
|
||||||
|
impl<'a> From<Cow<'a, str>> for Box<dyn Error> {
|
||||||
|
/// Converts a [`Cow`] into a box of dyn [`Error`].
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::error::Error;
|
||||||
|
/// use std::mem;
|
||||||
|
/// use std::borrow::Cow;
|
||||||
|
///
|
||||||
|
/// let a_cow_str_error = Cow::from("a str error");
|
||||||
|
/// let a_boxed_error = Box::<dyn Error>::from(a_cow_str_error);
|
||||||
|
/// assert!(mem::size_of::<Box<dyn Error>>() == mem::size_of_val(&a_boxed_error))
|
||||||
|
/// ```
|
||||||
|
fn from(err: Cow<'a, str>) -> Box<dyn Error> {
|
||||||
|
From::from(String::from(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "box_error", since = "1.8.0")]
|
||||||
|
impl<T: core::error::Error> core::error::Error for Box<T> {
|
||||||
|
#[allow(deprecated, deprecated_in_future)]
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
core::error::Error::description(&**self)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
|
fn cause(&self) -> Option<&dyn core::error::Error> {
|
||||||
|
core::error::Error::cause(&**self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
|
||||||
|
core::error::Error::source(&**self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -141,7 +141,7 @@ impl Display for TryReserveError {
|
|||||||
" because the computed capacity exceeded the collection's maximum"
|
" because the computed capacity exceeded the collection's maximum"
|
||||||
}
|
}
|
||||||
TryReserveErrorKind::AllocError { .. } => {
|
TryReserveErrorKind::AllocError { .. } => {
|
||||||
" because the memory allocator returned a error"
|
" because the memory allocator returned an error"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
fmt.write_str(reason)
|
fmt.write_str(reason)
|
||||||
@ -154,3 +154,6 @@ trait SpecExtend<I: IntoIterator> {
|
|||||||
/// Extends `self` with the contents of the given iterator.
|
/// Extends `self` with the contents of the given iterator.
|
||||||
fn spec_extend(&mut self, iter: I);
|
fn spec_extend(&mut self, iter: I);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "try_reserve", since = "1.57.0")]
|
||||||
|
impl core::error::Error for TryReserveError {}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
//! This library provides smart pointers and collections for managing
|
//! This library provides smart pointers and collections for managing
|
||||||
//! heap-allocated values.
|
//! heap-allocated values.
|
||||||
//!
|
//!
|
||||||
//! This library, like libcore, normally doesn’t need to be used directly
|
//! This library, like core, normally doesn’t need to be used directly
|
||||||
//! since its contents are re-exported in the [`std` crate](../std/index.html).
|
//! since its contents are re-exported in the [`std` crate](../std/index.html).
|
||||||
//! Crates that use the `#![no_std]` attribute however will typically
|
//! Crates that use the `#![no_std]` attribute however will typically
|
||||||
//! not depend on `std`, so they’d use this crate instead.
|
//! not depend on `std`, so they’d use this crate instead.
|
||||||
@ -58,10 +58,6 @@
|
|||||||
//! [`Rc`]: rc
|
//! [`Rc`]: rc
|
||||||
//! [`RefCell`]: core::cell
|
//! [`RefCell`]: core::cell
|
||||||
|
|
||||||
// To run liballoc tests without x.py without ending up with two copies of liballoc, Miri needs to be
|
|
||||||
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
|
|
||||||
// rustc itself never sets the feature, so this line has no affect there.
|
|
||||||
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
|
|
||||||
#![allow(unused_attributes)]
|
#![allow(unused_attributes)]
|
||||||
#![stable(feature = "alloc", since = "1.36.0")]
|
#![stable(feature = "alloc", since = "1.36.0")]
|
||||||
#![doc(
|
#![doc(
|
||||||
@ -75,23 +71,30 @@
|
|||||||
any(not(feature = "miri-test-libstd"), test, doctest),
|
any(not(feature = "miri-test-libstd"), test, doctest),
|
||||||
no_global_oom_handling,
|
no_global_oom_handling,
|
||||||
not(no_global_oom_handling),
|
not(no_global_oom_handling),
|
||||||
|
not(no_rc),
|
||||||
|
not(no_sync),
|
||||||
target_has_atomic = "ptr"
|
target_has_atomic = "ptr"
|
||||||
))]
|
))]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![needs_allocator]
|
#![needs_allocator]
|
||||||
|
// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be
|
||||||
|
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
|
||||||
|
// rustc itself never sets the feature, so this line has no affect there.
|
||||||
|
#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))]
|
||||||
//
|
//
|
||||||
// Lints:
|
// Lints:
|
||||||
#![deny(unsafe_op_in_unsafe_fn)]
|
#![deny(unsafe_op_in_unsafe_fn)]
|
||||||
|
#![deny(fuzzy_provenance_casts)]
|
||||||
#![warn(deprecated_in_future)]
|
#![warn(deprecated_in_future)]
|
||||||
#![warn(missing_debug_implementations)]
|
#![warn(missing_debug_implementations)]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
#![allow(explicit_outlives_requirements)]
|
#![allow(explicit_outlives_requirements)]
|
||||||
//
|
//
|
||||||
// Library features:
|
// Library features:
|
||||||
#![cfg_attr(not(no_global_oom_handling), feature(alloc_c_string))]
|
|
||||||
#![feature(alloc_layout_extra)]
|
#![feature(alloc_layout_extra)]
|
||||||
#![feature(allocator_api)]
|
#![feature(allocator_api)]
|
||||||
#![feature(array_chunks)]
|
#![feature(array_chunks)]
|
||||||
|
#![feature(array_into_iter_constructors)]
|
||||||
#![feature(array_methods)]
|
#![feature(array_methods)]
|
||||||
#![feature(array_windows)]
|
#![feature(array_windows)]
|
||||||
#![feature(assert_matches)]
|
#![feature(assert_matches)]
|
||||||
@ -99,39 +102,53 @@
|
|||||||
#![feature(coerce_unsized)]
|
#![feature(coerce_unsized)]
|
||||||
#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
|
#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
|
||||||
#![feature(const_box)]
|
#![feature(const_box)]
|
||||||
#![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))]
|
#![cfg_attr(not(no_global_oom_handling), feature(const_btree_len))]
|
||||||
#![cfg_attr(not(no_borrow), feature(const_cow_is_borrowed))]
|
#![cfg_attr(not(no_borrow), feature(const_cow_is_borrowed))]
|
||||||
#![feature(const_convert)]
|
#![feature(const_convert)]
|
||||||
#![feature(const_size_of_val)]
|
#![feature(const_size_of_val)]
|
||||||
#![feature(const_align_of_val)]
|
#![feature(const_align_of_val)]
|
||||||
#![feature(const_ptr_read)]
|
#![feature(const_ptr_read)]
|
||||||
|
#![feature(const_maybe_uninit_zeroed)]
|
||||||
#![feature(const_maybe_uninit_write)]
|
#![feature(const_maybe_uninit_write)]
|
||||||
#![feature(const_maybe_uninit_as_mut_ptr)]
|
#![feature(const_maybe_uninit_as_mut_ptr)]
|
||||||
#![feature(const_refs_to_cell)]
|
#![feature(const_refs_to_cell)]
|
||||||
#![feature(core_c_str)]
|
|
||||||
#![feature(core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![feature(core_ffi_c)]
|
#![feature(core_panic)]
|
||||||
#![feature(const_eval_select)]
|
#![feature(const_eval_select)]
|
||||||
#![feature(const_pin)]
|
#![feature(const_pin)]
|
||||||
|
#![feature(const_waker)]
|
||||||
#![feature(cstr_from_bytes_until_nul)]
|
#![feature(cstr_from_bytes_until_nul)]
|
||||||
#![feature(dispatch_from_dyn)]
|
#![feature(dispatch_from_dyn)]
|
||||||
|
#![feature(error_generic_member_access)]
|
||||||
|
#![feature(error_in_core)]
|
||||||
#![feature(exact_size_is_empty)]
|
#![feature(exact_size_is_empty)]
|
||||||
#![feature(extend_one)]
|
#![feature(extend_one)]
|
||||||
#![feature(fmt_internals)]
|
#![feature(fmt_internals)]
|
||||||
#![feature(fn_traits)]
|
#![feature(fn_traits)]
|
||||||
#![feature(hasher_prefixfree_extras)]
|
#![feature(hasher_prefixfree_extras)]
|
||||||
|
#![feature(inline_const)]
|
||||||
#![feature(inplace_iteration)]
|
#![feature(inplace_iteration)]
|
||||||
|
#![cfg_attr(test, feature(is_sorted))]
|
||||||
#![feature(iter_advance_by)]
|
#![feature(iter_advance_by)]
|
||||||
|
#![feature(iter_next_chunk)]
|
||||||
|
#![feature(iter_repeat_n)]
|
||||||
#![feature(layout_for_ptr)]
|
#![feature(layout_for_ptr)]
|
||||||
#![feature(maybe_uninit_slice)]
|
#![feature(maybe_uninit_slice)]
|
||||||
|
#![feature(maybe_uninit_uninit_array)]
|
||||||
|
#![feature(maybe_uninit_uninit_array_transpose)]
|
||||||
#![cfg_attr(test, feature(new_uninit))]
|
#![cfg_attr(test, feature(new_uninit))]
|
||||||
#![feature(nonnull_slice_from_raw_parts)]
|
#![feature(nonnull_slice_from_raw_parts)]
|
||||||
#![feature(pattern)]
|
#![feature(pattern)]
|
||||||
|
#![feature(pointer_byte_offsets)]
|
||||||
|
#![feature(provide_any)]
|
||||||
#![feature(ptr_internals)]
|
#![feature(ptr_internals)]
|
||||||
#![feature(ptr_metadata)]
|
#![feature(ptr_metadata)]
|
||||||
#![feature(ptr_sub_ptr)]
|
#![feature(ptr_sub_ptr)]
|
||||||
#![feature(receiver_trait)]
|
#![feature(receiver_trait)]
|
||||||
|
#![feature(saturating_int_impl)]
|
||||||
#![feature(set_ptr_value)]
|
#![feature(set_ptr_value)]
|
||||||
|
#![feature(sized_type_properties)]
|
||||||
|
#![feature(slice_from_ptr_range)]
|
||||||
#![feature(slice_group_by)]
|
#![feature(slice_group_by)]
|
||||||
#![feature(slice_ptr_get)]
|
#![feature(slice_ptr_get)]
|
||||||
#![feature(slice_ptr_len)]
|
#![feature(slice_ptr_len)]
|
||||||
@ -141,15 +158,17 @@
|
|||||||
#![feature(trusted_len)]
|
#![feature(trusted_len)]
|
||||||
#![feature(trusted_random_access)]
|
#![feature(trusted_random_access)]
|
||||||
#![feature(try_trait_v2)]
|
#![feature(try_trait_v2)]
|
||||||
|
#![feature(tuple_trait)]
|
||||||
#![feature(unchecked_math)]
|
#![feature(unchecked_math)]
|
||||||
#![feature(unicode_internals)]
|
#![feature(unicode_internals)]
|
||||||
#![feature(unsize)]
|
#![feature(unsize)]
|
||||||
|
#![feature(utf8_chunks)]
|
||||||
|
#![feature(std_internals)]
|
||||||
//
|
//
|
||||||
// Language features:
|
// Language features:
|
||||||
#![feature(allocator_internals)]
|
#![feature(allocator_internals)]
|
||||||
#![feature(allow_internal_unstable)]
|
#![feature(allow_internal_unstable)]
|
||||||
#![feature(associated_type_bounds)]
|
#![feature(associated_type_bounds)]
|
||||||
#![feature(box_syntax)]
|
|
||||||
#![feature(cfg_sanitize)]
|
#![feature(cfg_sanitize)]
|
||||||
#![feature(const_deref)]
|
#![feature(const_deref)]
|
||||||
#![feature(const_mut_refs)]
|
#![feature(const_mut_refs)]
|
||||||
@ -163,19 +182,21 @@
|
|||||||
#![cfg_attr(not(test), feature(generator_trait))]
|
#![cfg_attr(not(test), feature(generator_trait))]
|
||||||
#![feature(hashmap_internals)]
|
#![feature(hashmap_internals)]
|
||||||
#![feature(lang_items)]
|
#![feature(lang_items)]
|
||||||
#![feature(let_else)]
|
|
||||||
#![feature(min_specialization)]
|
#![feature(min_specialization)]
|
||||||
#![feature(negative_impls)]
|
#![feature(negative_impls)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(nll)] // Not necessary, but here to test the `nll` feature.
|
|
||||||
#![feature(rustc_allow_const_fn_unstable)]
|
#![feature(rustc_allow_const_fn_unstable)]
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
#![feature(pointer_is_aligned)]
|
||||||
#![feature(slice_internals)]
|
#![feature(slice_internals)]
|
||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
|
#![feature(stmt_expr_attributes)]
|
||||||
#![cfg_attr(test, feature(test))]
|
#![cfg_attr(test, feature(test))]
|
||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
#![feature(unsized_fn_params)]
|
#![feature(unsized_fn_params)]
|
||||||
#![feature(c_unwind)]
|
#![feature(c_unwind)]
|
||||||
|
#![feature(with_negative_coherence)]
|
||||||
|
#![cfg_attr(test, feature(panic_update_hook))]
|
||||||
//
|
//
|
||||||
// Rustdoc features:
|
// Rustdoc features:
|
||||||
#![feature(doc_cfg)]
|
#![feature(doc_cfg)]
|
||||||
@ -192,6 +213,8 @@
|
|||||||
extern crate std;
|
extern crate std;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod testing;
|
||||||
|
|
||||||
// Module with internal macros used by other modules (needs to be included before other modules).
|
// Module with internal macros used by other modules (needs to be included before other modules).
|
||||||
#[cfg(not(no_macros))]
|
#[cfg(not(no_macros))]
|
||||||
@ -218,7 +241,7 @@ mod boxed {
|
|||||||
#[cfg(not(no_borrow))]
|
#[cfg(not(no_borrow))]
|
||||||
pub mod borrow;
|
pub mod borrow;
|
||||||
pub mod collections;
|
pub mod collections;
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))]
|
||||||
pub mod ffi;
|
pub mod ffi;
|
||||||
#[cfg(not(no_fmt))]
|
#[cfg(not(no_fmt))]
|
||||||
pub mod fmt;
|
pub mod fmt;
|
||||||
@ -229,10 +252,9 @@ pub mod slice;
|
|||||||
pub mod str;
|
pub mod str;
|
||||||
#[cfg(not(no_string))]
|
#[cfg(not(no_string))]
|
||||||
pub mod string;
|
pub mod string;
|
||||||
#[cfg(not(no_sync))]
|
#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
|
||||||
#[cfg(target_has_atomic = "ptr")]
|
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
#[cfg(all(not(no_global_oom_handling), target_has_atomic = "ptr"))]
|
#[cfg(all(not(no_global_oom_handling), not(no_rc), not(no_sync), target_has_atomic = "ptr"))]
|
||||||
pub mod task;
|
pub mod task;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
@ -243,3 +265,20 @@ pub mod vec;
|
|||||||
pub mod __export {
|
pub mod __export {
|
||||||
pub use core::format_args;
|
pub use core::format_args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[allow(dead_code)] // Not used in all configurations
|
||||||
|
pub(crate) mod test_helpers {
|
||||||
|
/// Copied from `std::test_helpers::test_rng`, since these tests rely on the
|
||||||
|
/// seed not being the same for every RNG invocation too.
|
||||||
|
pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
|
||||||
|
use std::hash::{BuildHasher, Hash, Hasher};
|
||||||
|
let mut hasher = std::collections::hash_map::RandomState::new().build_hasher();
|
||||||
|
std::panic::Location::caller().hash(&mut hasher);
|
||||||
|
let hc64 = hasher.finish();
|
||||||
|
let seed_vec =
|
||||||
|
hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<crate::vec::Vec<u8>>();
|
||||||
|
let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap();
|
||||||
|
rand::SeedableRng::from_seed(seed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
use core::alloc::LayoutError;
|
use core::alloc::LayoutError;
|
||||||
use core::cmp;
|
use core::cmp;
|
||||||
use core::intrinsics;
|
use core::intrinsics;
|
||||||
use core::mem::{self, ManuallyDrop, MaybeUninit};
|
use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
|
||||||
use core::ops::Drop;
|
use core::ops::Drop;
|
||||||
use core::ptr::{self, NonNull, Unique};
|
use core::ptr::{self, NonNull, Unique};
|
||||||
use core::slice;
|
use core::slice;
|
||||||
@ -177,7 +177,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self {
|
fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self {
|
||||||
// Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
|
// Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
|
||||||
if mem::size_of::<T>() == 0 || capacity == 0 {
|
if T::IS_ZST || capacity == 0 {
|
||||||
Self::new_in(alloc)
|
Self::new_in(alloc)
|
||||||
} else {
|
} else {
|
||||||
// We avoid `unwrap_or_else` here because it bloats the amount of
|
// We avoid `unwrap_or_else` here because it bloats the amount of
|
||||||
@ -212,7 +212,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||||||
|
|
||||||
fn try_allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Result<Self, TryReserveError> {
|
fn try_allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Result<Self, TryReserveError> {
|
||||||
// Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
|
// Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
|
||||||
if mem::size_of::<T>() == 0 || capacity == 0 {
|
if T::IS_ZST || capacity == 0 {
|
||||||
return Ok(Self::new_in(alloc));
|
return Ok(Self::new_in(alloc));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||||||
/// This will always be `usize::MAX` if `T` is zero-sized.
|
/// This will always be `usize::MAX` if `T` is zero-sized.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn capacity(&self) -> usize {
|
pub fn capacity(&self) -> usize {
|
||||||
if mem::size_of::<T>() == 0 { usize::MAX } else { self.cap }
|
if T::IS_ZST { usize::MAX } else { self.cap }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a shared reference to the allocator backing this `RawVec`.
|
/// Returns a shared reference to the allocator backing this `RawVec`.
|
||||||
@ -271,7 +271,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
|
fn current_memory(&self) -> Option<(NonNull<u8>, Layout)> {
|
||||||
if mem::size_of::<T>() == 0 || self.cap == 0 {
|
if T::IS_ZST || self.cap == 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
// We have an allocated chunk of memory, so we can bypass runtime
|
// We have an allocated chunk of memory, so we can bypass runtime
|
||||||
@ -419,7 +419,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||||||
// This is ensured by the calling contexts.
|
// This is ensured by the calling contexts.
|
||||||
debug_assert!(additional > 0);
|
debug_assert!(additional > 0);
|
||||||
|
|
||||||
if mem::size_of::<T>() == 0 {
|
if T::IS_ZST {
|
||||||
// Since we return a capacity of `usize::MAX` when `elem_size` is
|
// Since we return a capacity of `usize::MAX` when `elem_size` is
|
||||||
// 0, getting to here necessarily means the `RawVec` is overfull.
|
// 0, getting to here necessarily means the `RawVec` is overfull.
|
||||||
return Err(CapacityOverflow.into());
|
return Err(CapacityOverflow.into());
|
||||||
@ -445,7 +445,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||||||
// `grow_amortized`, but this method is usually instantiated less often so
|
// `grow_amortized`, but this method is usually instantiated less often so
|
||||||
// it's less critical.
|
// it's less critical.
|
||||||
fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
|
fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserveError> {
|
||||||
if mem::size_of::<T>() == 0 {
|
if T::IS_ZST {
|
||||||
// Since we return a capacity of `usize::MAX` when the type size is
|
// Since we return a capacity of `usize::MAX` when the type size is
|
||||||
// 0, getting to here necessarily means the `RawVec` is overfull.
|
// 0, getting to here necessarily means the `RawVec` is overfull.
|
||||||
return Err(CapacityOverflow.into());
|
return Err(CapacityOverflow.into());
|
||||||
@ -460,7 +460,7 @@ impl<T, A: Allocator> RawVec<T, A> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> {
|
fn shrink(&mut self, cap: usize) -> Result<(), TryReserveError> {
|
||||||
assert!(cap <= self.capacity(), "Tried to shrink to a larger capacity");
|
assert!(cap <= self.capacity(), "Tried to shrink to a larger capacity");
|
||||||
|
|
||||||
|
@ -1,84 +1,14 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
|
||||||
//! A dynamically-sized view into a contiguous sequence, `[T]`.
|
//! Utilities for the slice primitive type.
|
||||||
//!
|
//!
|
||||||
//! *[See also the slice primitive type](slice).*
|
//! *[See also the slice primitive type](slice).*
|
||||||
//!
|
//!
|
||||||
//! Slices are a view into a block of memory represented as a pointer and a
|
//! Most of the structs in this module are iterator types which can only be created
|
||||||
//! length.
|
//! using a certain function. For example, `slice.iter()` yields an [`Iter`].
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! A few functions are provided to create a slice from a value reference
|
||||||
//! // slicing a Vec
|
//! or from a raw pointer.
|
||||||
//! let vec = vec![1, 2, 3];
|
|
||||||
//! let int_slice = &vec[..];
|
|
||||||
//! // coercing an array to a slice
|
|
||||||
//! let str_slice: &[&str] = &["one", "two", "three"];
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Slices are either mutable or shared. The shared slice type is `&[T]`,
|
|
||||||
//! while the mutable slice type is `&mut [T]`, where `T` represents the element
|
|
||||||
//! type. For example, you can mutate the block of memory that a mutable slice
|
|
||||||
//! points to:
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//! let x = &mut [1, 2, 3];
|
|
||||||
//! x[1] = 7;
|
|
||||||
//! assert_eq!(x, &[1, 7, 3]);
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Here are some of the things this module contains:
|
|
||||||
//!
|
|
||||||
//! ## Structs
|
|
||||||
//!
|
|
||||||
//! There are several structs that are useful for slices, such as [`Iter`], which
|
|
||||||
//! represents iteration over a slice.
|
|
||||||
//!
|
|
||||||
//! ## Trait Implementations
|
|
||||||
//!
|
|
||||||
//! There are several implementations of common traits for slices. Some examples
|
|
||||||
//! include:
|
|
||||||
//!
|
|
||||||
//! * [`Clone`]
|
|
||||||
//! * [`Eq`], [`Ord`] - for slices whose element type are [`Eq`] or [`Ord`].
|
|
||||||
//! * [`Hash`] - for slices whose element type is [`Hash`].
|
|
||||||
//!
|
|
||||||
//! ## Iteration
|
|
||||||
//!
|
|
||||||
//! The slices implement `IntoIterator`. The iterator yields references to the
|
|
||||||
//! slice elements.
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//! let numbers = &[0, 1, 2];
|
|
||||||
//! for n in numbers {
|
|
||||||
//! println!("{n} is a number!");
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! The mutable slice yields mutable references to the elements:
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//! let mut scores = [7, 8, 9];
|
|
||||||
//! for score in &mut scores[..] {
|
|
||||||
//! *score += 1;
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! This iterator yields mutable references to the slice's elements, so while
|
|
||||||
//! the element type of the slice is `i32`, the element type of the iterator is
|
|
||||||
//! `&mut i32`.
|
|
||||||
//!
|
|
||||||
//! * [`.iter`] and [`.iter_mut`] are the explicit methods to return the default
|
|
||||||
//! iterators.
|
|
||||||
//! * Further methods that return iterators are [`.split`], [`.splitn`],
|
|
||||||
//! [`.chunks`], [`.windows`] and more.
|
|
||||||
//!
|
|
||||||
//! [`Hash`]: core::hash::Hash
|
|
||||||
//! [`.iter`]: slice::iter
|
|
||||||
//! [`.iter_mut`]: slice::iter_mut
|
|
||||||
//! [`.split`]: slice::split
|
|
||||||
//! [`.splitn`]: slice::splitn
|
|
||||||
//! [`.chunks`]: slice::chunks
|
|
||||||
//! [`.windows`]: slice::windows
|
|
||||||
#![stable(feature = "rust1", since = "1.0.0")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
// Many of the usings in this module are only used in the test configuration.
|
// Many of the usings in this module are only used in the test configuration.
|
||||||
// It's cleaner to just turn off the unused_imports warning than to fix them.
|
// It's cleaner to just turn off the unused_imports warning than to fix them.
|
||||||
@ -88,20 +18,23 @@ use core::borrow::{Borrow, BorrowMut};
|
|||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
use core::cmp::Ordering::{self, Less};
|
use core::cmp::Ordering::{self, Less};
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
use core::mem;
|
use core::mem::{self, SizedTypeProperties};
|
||||||
#[cfg(not(no_global_oom_handling))]
|
|
||||||
use core::mem::size_of;
|
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
use core::slice::sort;
|
||||||
|
|
||||||
use crate::alloc::Allocator;
|
use crate::alloc::Allocator;
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
use crate::alloc::Global;
|
use crate::alloc::{self, Global};
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
use crate::borrow::ToOwned;
|
use crate::borrow::ToOwned;
|
||||||
use crate::boxed::Box;
|
use crate::boxed::Box;
|
||||||
use crate::vec::Vec;
|
use crate::vec::Vec;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
#[unstable(feature = "slice_range", issue = "76393")]
|
#[unstable(feature = "slice_range", issue = "76393")]
|
||||||
pub use core::slice::range;
|
pub use core::slice::range;
|
||||||
#[unstable(feature = "array_chunks", issue = "74985")]
|
#[unstable(feature = "array_chunks", issue = "74985")]
|
||||||
@ -116,6 +49,8 @@ pub use core::slice::EscapeAscii;
|
|||||||
pub use core::slice::SliceIndex;
|
pub use core::slice::SliceIndex;
|
||||||
#[stable(feature = "from_ref", since = "1.28.0")]
|
#[stable(feature = "from_ref", since = "1.28.0")]
|
||||||
pub use core::slice::{from_mut, from_ref};
|
pub use core::slice::{from_mut, from_ref};
|
||||||
|
#[unstable(feature = "slice_from_ptr_range", issue = "89792")]
|
||||||
|
pub use core::slice::{from_mut_ptr_range, from_ptr_range};
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use core::slice::{from_raw_parts, from_raw_parts_mut};
|
pub use core::slice::{from_raw_parts, from_raw_parts_mut};
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
@ -275,7 +210,7 @@ impl<T> [T] {
|
|||||||
where
|
where
|
||||||
T: Ord,
|
T: Ord,
|
||||||
{
|
{
|
||||||
merge_sort(self, |a, b| a.lt(b));
|
stable_sort(self, T::lt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sorts the slice with a comparator function.
|
/// Sorts the slice with a comparator function.
|
||||||
@ -331,7 +266,7 @@ impl<T> [T] {
|
|||||||
where
|
where
|
||||||
F: FnMut(&T, &T) -> Ordering,
|
F: FnMut(&T, &T) -> Ordering,
|
||||||
{
|
{
|
||||||
merge_sort(self, |a, b| compare(a, b) == Less);
|
stable_sort(self, |a, b| compare(a, b) == Less);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sorts the slice with a key extraction function.
|
/// Sorts the slice with a key extraction function.
|
||||||
@ -374,7 +309,7 @@ impl<T> [T] {
|
|||||||
F: FnMut(&T) -> K,
|
F: FnMut(&T) -> K,
|
||||||
K: Ord,
|
K: Ord,
|
||||||
{
|
{
|
||||||
merge_sort(self, |a, b| f(a).lt(&f(b)));
|
stable_sort(self, |a, b| f(a).lt(&f(b)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sorts the slice with a key extraction function.
|
/// Sorts the slice with a key extraction function.
|
||||||
@ -530,7 +465,7 @@ impl<T> [T] {
|
|||||||
hack::into_vec(self)
|
hack::into_vec(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a vector by repeating a slice `n` times.
|
/// Creates a vector by copying a slice `n` times.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
@ -725,7 +660,7 @@ impl [u8] {
|
|||||||
///
|
///
|
||||||
/// ```error
|
/// ```error
|
||||||
/// error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predica
|
/// error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predica
|
||||||
/// --> src/liballoc/slice.rs:608:6
|
/// --> library/alloc/src/slice.rs:608:6
|
||||||
/// |
|
/// |
|
||||||
/// 608 | impl<T: Clone, V: Borrow<[T]>> Concat for [V] {
|
/// 608 | impl<T: Clone, V: Borrow<[T]>> Concat for [V] {
|
||||||
/// | ^ unconstrained type parameter
|
/// | ^ unconstrained type parameter
|
||||||
@ -836,14 +771,14 @@ impl<T: Clone, V: Borrow<[T]>> Join<&[T]> for [V] {
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T> Borrow<[T]> for Vec<T> {
|
impl<T, A: Allocator> Borrow<[T]> for Vec<T, A> {
|
||||||
fn borrow(&self) -> &[T] {
|
fn borrow(&self) -> &[T] {
|
||||||
&self[..]
|
&self[..]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T> BorrowMut<[T]> for Vec<T> {
|
impl<T, A: Allocator> BorrowMut<[T]> for Vec<T, A> {
|
||||||
fn borrow_mut(&mut self) -> &mut [T] {
|
fn borrow_mut(&mut self) -> &mut [T] {
|
||||||
&mut self[..]
|
&mut self[..]
|
||||||
}
|
}
|
||||||
@ -881,324 +816,52 @@ impl<T: Clone> ToOwned for [T] {
|
|||||||
// Sorting
|
// Sorting
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// Inserts `v[0]` into pre-sorted sequence `v[1..]` so that whole `v[..]` becomes sorted.
|
#[inline]
|
||||||
///
|
|
||||||
/// This is the integral subroutine of insertion sort.
|
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
|
fn stable_sort<T, F>(v: &mut [T], mut is_less: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&T, &T) -> bool,
|
F: FnMut(&T, &T) -> bool,
|
||||||
{
|
{
|
||||||
if v.len() >= 2 && is_less(&v[1], &v[0]) {
|
if T::IS_ZST {
|
||||||
unsafe {
|
// Sorting has no meaningful behavior on zero-sized types. Do nothing.
|
||||||
// There are three ways to implement insertion here:
|
|
||||||
//
|
|
||||||
// 1. Swap adjacent elements until the first one gets to its final destination.
|
|
||||||
// However, this way we copy data around more than is necessary. If elements are big
|
|
||||||
// structures (costly to copy), this method will be slow.
|
|
||||||
//
|
|
||||||
// 2. Iterate until the right place for the first element is found. Then shift the
|
|
||||||
// elements succeeding it to make room for it and finally place it into the
|
|
||||||
// remaining hole. This is a good method.
|
|
||||||
//
|
|
||||||
// 3. Copy the first element into a temporary variable. Iterate until the right place
|
|
||||||
// for it is found. As we go along, copy every traversed element into the slot
|
|
||||||
// preceding it. Finally, copy data from the temporary variable into the remaining
|
|
||||||
// hole. This method is very good. Benchmarks demonstrated slightly better
|
|
||||||
// performance than with the 2nd method.
|
|
||||||
//
|
|
||||||
// All methods were benchmarked, and the 3rd showed best results. So we chose that one.
|
|
||||||
let tmp = mem::ManuallyDrop::new(ptr::read(&v[0]));
|
|
||||||
|
|
||||||
// Intermediate state of the insertion process is always tracked by `hole`, which
|
|
||||||
// serves two purposes:
|
|
||||||
// 1. Protects integrity of `v` from panics in `is_less`.
|
|
||||||
// 2. Fills the remaining hole in `v` in the end.
|
|
||||||
//
|
|
||||||
// Panic safety:
|
|
||||||
//
|
|
||||||
// If `is_less` panics at any point during the process, `hole` will get dropped and
|
|
||||||
// fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it
|
|
||||||
// initially held exactly once.
|
|
||||||
let mut hole = InsertionHole { src: &*tmp, dest: &mut v[1] };
|
|
||||||
ptr::copy_nonoverlapping(&v[1], &mut v[0], 1);
|
|
||||||
|
|
||||||
for i in 2..v.len() {
|
|
||||||
if !is_less(&v[i], &*tmp) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ptr::copy_nonoverlapping(&v[i], &mut v[i - 1], 1);
|
|
||||||
hole.dest = &mut v[i];
|
|
||||||
}
|
|
||||||
// `hole` gets dropped and thus copies `tmp` into the remaining hole in `v`.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// When dropped, copies from `src` into `dest`.
|
|
||||||
struct InsertionHole<T> {
|
|
||||||
src: *const T,
|
|
||||||
dest: *mut T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Drop for InsertionHole<T> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
ptr::copy_nonoverlapping(self.src, self.dest, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Merges non-decreasing runs `v[..mid]` and `v[mid..]` using `buf` as temporary storage, and
|
|
||||||
/// stores the result into `v[..]`.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// The two slices must be non-empty and `mid` must be in bounds. Buffer `buf` must be long enough
|
|
||||||
/// to hold a copy of the shorter slice. Also, `T` must not be a zero-sized type.
|
|
||||||
#[cfg(not(no_global_oom_handling))]
|
|
||||||
unsafe fn merge<T, F>(v: &mut [T], mid: usize, buf: *mut T, is_less: &mut F)
|
|
||||||
where
|
|
||||||
F: FnMut(&T, &T) -> bool,
|
|
||||||
{
|
|
||||||
let len = v.len();
|
|
||||||
let v = v.as_mut_ptr();
|
|
||||||
let (v_mid, v_end) = unsafe { (v.add(mid), v.add(len)) };
|
|
||||||
|
|
||||||
// The merge process first copies the shorter run into `buf`. Then it traces the newly copied
|
|
||||||
// run and the longer run forwards (or backwards), comparing their next unconsumed elements and
|
|
||||||
// copying the lesser (or greater) one into `v`.
|
|
||||||
//
|
|
||||||
// As soon as the shorter run is fully consumed, the process is done. If the longer run gets
|
|
||||||
// consumed first, then we must copy whatever is left of the shorter run into the remaining
|
|
||||||
// hole in `v`.
|
|
||||||
//
|
|
||||||
// Intermediate state of the process is always tracked by `hole`, which serves two purposes:
|
|
||||||
// 1. Protects integrity of `v` from panics in `is_less`.
|
|
||||||
// 2. Fills the remaining hole in `v` if the longer run gets consumed first.
|
|
||||||
//
|
|
||||||
// Panic safety:
|
|
||||||
//
|
|
||||||
// If `is_less` panics at any point during the process, `hole` will get dropped and fill the
|
|
||||||
// hole in `v` with the unconsumed range in `buf`, thus ensuring that `v` still holds every
|
|
||||||
// object it initially held exactly once.
|
|
||||||
let mut hole;
|
|
||||||
|
|
||||||
if mid <= len - mid {
|
|
||||||
// The left run is shorter.
|
|
||||||
unsafe {
|
|
||||||
ptr::copy_nonoverlapping(v, buf, mid);
|
|
||||||
hole = MergeHole { start: buf, end: buf.add(mid), dest: v };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initially, these pointers point to the beginnings of their arrays.
|
|
||||||
let left = &mut hole.start;
|
|
||||||
let mut right = v_mid;
|
|
||||||
let out = &mut hole.dest;
|
|
||||||
|
|
||||||
while *left < hole.end && right < v_end {
|
|
||||||
// Consume the lesser side.
|
|
||||||
// If equal, prefer the left run to maintain stability.
|
|
||||||
unsafe {
|
|
||||||
let to_copy = if is_less(&*right, &**left) {
|
|
||||||
get_and_increment(&mut right)
|
|
||||||
} else {
|
|
||||||
get_and_increment(left)
|
|
||||||
};
|
|
||||||
ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// The right run is shorter.
|
|
||||||
unsafe {
|
|
||||||
ptr::copy_nonoverlapping(v_mid, buf, len - mid);
|
|
||||||
hole = MergeHole { start: buf, end: buf.add(len - mid), dest: v_mid };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initially, these pointers point past the ends of their arrays.
|
|
||||||
let left = &mut hole.dest;
|
|
||||||
let right = &mut hole.end;
|
|
||||||
let mut out = v_end;
|
|
||||||
|
|
||||||
while v < *left && buf < *right {
|
|
||||||
// Consume the greater side.
|
|
||||||
// If equal, prefer the right run to maintain stability.
|
|
||||||
unsafe {
|
|
||||||
let to_copy = if is_less(&*right.offset(-1), &*left.offset(-1)) {
|
|
||||||
decrement_and_get(left)
|
|
||||||
} else {
|
|
||||||
decrement_and_get(right)
|
|
||||||
};
|
|
||||||
ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of
|
|
||||||
// it will now be copied into the hole in `v`.
|
|
||||||
|
|
||||||
unsafe fn get_and_increment<T>(ptr: &mut *mut T) -> *mut T {
|
|
||||||
let old = *ptr;
|
|
||||||
*ptr = unsafe { ptr.offset(1) };
|
|
||||||
old
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn decrement_and_get<T>(ptr: &mut *mut T) -> *mut T {
|
|
||||||
*ptr = unsafe { ptr.offset(-1) };
|
|
||||||
*ptr
|
|
||||||
}
|
|
||||||
|
|
||||||
// When dropped, copies the range `start..end` into `dest..`.
|
|
||||||
struct MergeHole<T> {
|
|
||||||
start: *mut T,
|
|
||||||
end: *mut T,
|
|
||||||
dest: *mut T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Drop for MergeHole<T> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
// `T` is not a zero-sized type, and these are pointers into a slice's elements.
|
|
||||||
unsafe {
|
|
||||||
let len = self.end.sub_ptr(self.start);
|
|
||||||
ptr::copy_nonoverlapping(self.start, self.dest, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This merge sort borrows some (but not all) ideas from TimSort, which is described in detail
|
|
||||||
/// [here](https://github.com/python/cpython/blob/main/Objects/listsort.txt).
|
|
||||||
///
|
|
||||||
/// The algorithm identifies strictly descending and non-descending subsequences, which are called
|
|
||||||
/// natural runs. There is a stack of pending runs yet to be merged. Each newly found run is pushed
|
|
||||||
/// onto the stack, and then some pairs of adjacent runs are merged until these two invariants are
|
|
||||||
/// satisfied:
|
|
||||||
///
|
|
||||||
/// 1. for every `i` in `1..runs.len()`: `runs[i - 1].len > runs[i].len`
|
|
||||||
/// 2. for every `i` in `2..runs.len()`: `runs[i - 2].len > runs[i - 1].len + runs[i].len`
|
|
||||||
///
|
|
||||||
/// The invariants ensure that the total running time is *O*(*n* \* log(*n*)) worst-case.
|
|
||||||
#[cfg(not(no_global_oom_handling))]
|
|
||||||
fn merge_sort<T, F>(v: &mut [T], mut is_less: F)
|
|
||||||
where
|
|
||||||
F: FnMut(&T, &T) -> bool,
|
|
||||||
{
|
|
||||||
// Slices of up to this length get sorted using insertion sort.
|
|
||||||
const MAX_INSERTION: usize = 20;
|
|
||||||
// Very short runs are extended using insertion sort to span at least this many elements.
|
|
||||||
const MIN_RUN: usize = 10;
|
|
||||||
|
|
||||||
// Sorting has no meaningful behavior on zero-sized types.
|
|
||||||
if size_of::<T>() == 0 {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let len = v.len();
|
let elem_alloc_fn = |len: usize| -> *mut T {
|
||||||
|
// SAFETY: Creating the layout is safe as long as merge_sort never calls this with len >
|
||||||
|
// v.len(). Alloc in general will only be used as 'shadow-region' to store temporary swap
|
||||||
|
// elements.
|
||||||
|
unsafe { alloc::alloc(alloc::Layout::array::<T>(len).unwrap_unchecked()) as *mut T }
|
||||||
|
};
|
||||||
|
|
||||||
// Short arrays get sorted in-place via insertion sort to avoid allocations.
|
let elem_dealloc_fn = |buf_ptr: *mut T, len: usize| {
|
||||||
if len <= MAX_INSERTION {
|
// SAFETY: Creating the layout is safe as long as merge_sort never calls this with len >
|
||||||
if len >= 2 {
|
// v.len(). The caller must ensure that buf_ptr was created by elem_alloc_fn with the same
|
||||||
for i in (0..len - 1).rev() {
|
// len.
|
||||||
insert_head(&mut v[i..], &mut is_less);
|
unsafe {
|
||||||
}
|
alloc::dealloc(buf_ptr as *mut u8, alloc::Layout::array::<T>(len).unwrap_unchecked());
|
||||||
}
|
}
|
||||||
return;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
// Allocate a buffer to use as scratch memory. We keep the length 0 so we can keep in it
|
let run_alloc_fn = |len: usize| -> *mut sort::TimSortRun {
|
||||||
// shallow copies of the contents of `v` without risking the dtors running on copies if
|
// SAFETY: Creating the layout is safe as long as merge_sort never calls this with an
|
||||||
// `is_less` panics. When merging two sorted runs, this buffer holds a copy of the shorter run,
|
// obscene length or 0.
|
||||||
// which will always have length at most `len / 2`.
|
unsafe {
|
||||||
let mut buf = Vec::with_capacity(len / 2);
|
alloc::alloc(alloc::Layout::array::<sort::TimSortRun>(len).unwrap_unchecked())
|
||||||
|
as *mut sort::TimSortRun
|
||||||
// In order to identify natural runs in `v`, we traverse it backwards. That might seem like a
|
|
||||||
// strange decision, but consider the fact that merges more often go in the opposite direction
|
|
||||||
// (forwards). According to benchmarks, merging forwards is slightly faster than merging
|
|
||||||
// backwards. To conclude, identifying runs by traversing backwards improves performance.
|
|
||||||
let mut runs = vec![];
|
|
||||||
let mut end = len;
|
|
||||||
while end > 0 {
|
|
||||||
// Find the next natural run, and reverse it if it's strictly descending.
|
|
||||||
let mut start = end - 1;
|
|
||||||
if start > 0 {
|
|
||||||
start -= 1;
|
|
||||||
unsafe {
|
|
||||||
if is_less(v.get_unchecked(start + 1), v.get_unchecked(start)) {
|
|
||||||
while start > 0 && is_less(v.get_unchecked(start), v.get_unchecked(start - 1)) {
|
|
||||||
start -= 1;
|
|
||||||
}
|
|
||||||
v[start..end].reverse();
|
|
||||||
} else {
|
|
||||||
while start > 0 && !is_less(v.get_unchecked(start), v.get_unchecked(start - 1))
|
|
||||||
{
|
|
||||||
start -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Insert some more elements into the run if it's too short. Insertion sort is faster than
|
let run_dealloc_fn = |buf_ptr: *mut sort::TimSortRun, len: usize| {
|
||||||
// merge sort on short sequences, so this significantly improves performance.
|
// SAFETY: The caller must ensure that buf_ptr was created by elem_alloc_fn with the same
|
||||||
while start > 0 && end - start < MIN_RUN {
|
// len.
|
||||||
start -= 1;
|
unsafe {
|
||||||
insert_head(&mut v[start..end], &mut is_less);
|
alloc::dealloc(
|
||||||
|
buf_ptr as *mut u8,
|
||||||
|
alloc::Layout::array::<sort::TimSortRun>(len).unwrap_unchecked(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Push this run onto the stack.
|
sort::merge_sort(v, &mut is_less, elem_alloc_fn, elem_dealloc_fn, run_alloc_fn, run_dealloc_fn);
|
||||||
runs.push(Run { start, len: end - start });
|
|
||||||
end = start;
|
|
||||||
|
|
||||||
// Merge some pairs of adjacent runs to satisfy the invariants.
|
|
||||||
while let Some(r) = collapse(&runs) {
|
|
||||||
let left = runs[r + 1];
|
|
||||||
let right = runs[r];
|
|
||||||
unsafe {
|
|
||||||
merge(
|
|
||||||
&mut v[left.start..right.start + right.len],
|
|
||||||
left.len,
|
|
||||||
buf.as_mut_ptr(),
|
|
||||||
&mut is_less,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
runs[r] = Run { start: left.start, len: left.len + right.len };
|
|
||||||
runs.remove(r + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, exactly one run must remain in the stack.
|
|
||||||
debug_assert!(runs.len() == 1 && runs[0].start == 0 && runs[0].len == len);
|
|
||||||
|
|
||||||
// Examines the stack of runs and identifies the next pair of runs to merge. More specifically,
|
|
||||||
// if `Some(r)` is returned, that means `runs[r]` and `runs[r + 1]` must be merged next. If the
|
|
||||||
// algorithm should continue building a new run instead, `None` is returned.
|
|
||||||
//
|
|
||||||
// TimSort is infamous for its buggy implementations, as described here:
|
|
||||||
// http://envisage-project.eu/timsort-specification-and-verification/
|
|
||||||
//
|
|
||||||
// The gist of the story is: we must enforce the invariants on the top four runs on the stack.
|
|
||||||
// Enforcing them on just top three is not sufficient to ensure that the invariants will still
|
|
||||||
// hold for *all* runs in the stack.
|
|
||||||
//
|
|
||||||
// This function correctly checks invariants for the top four runs. Additionally, if the top
|
|
||||||
// run starts at index 0, it will always demand a merge operation until the stack is fully
|
|
||||||
// collapsed, in order to complete the sort.
|
|
||||||
#[inline]
|
|
||||||
fn collapse(runs: &[Run]) -> Option<usize> {
|
|
||||||
let n = runs.len();
|
|
||||||
if n >= 2
|
|
||||||
&& (runs[n - 1].start == 0
|
|
||||||
|| runs[n - 2].len <= runs[n - 1].len
|
|
||||||
|| (n >= 3 && runs[n - 3].len <= runs[n - 2].len + runs[n - 1].len)
|
|
||||||
|| (n >= 4 && runs[n - 4].len <= runs[n - 3].len + runs[n - 2].len))
|
|
||||||
{
|
|
||||||
if n >= 3 && runs[n - 3].len < runs[n - 1].len { Some(n - 3) } else { Some(n - 2) }
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
struct Run {
|
|
||||||
start: usize,
|
|
||||||
len: usize,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use crate::alloc::{Allocator, Global};
|
use crate::alloc::{Allocator, Global};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::iter::{FusedIterator, TrustedLen};
|
use core::iter::{FusedIterator, TrustedLen};
|
||||||
use core::mem;
|
use core::mem::{self, ManuallyDrop, SizedTypeProperties};
|
||||||
use core::ptr::{self, NonNull};
|
use core::ptr::{self, NonNull};
|
||||||
use core::slice::{self};
|
use core::slice::{self};
|
||||||
|
|
||||||
@ -67,6 +67,77 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> {
|
|||||||
pub fn allocator(&self) -> &A {
|
pub fn allocator(&self) -> &A {
|
||||||
unsafe { self.vec.as_ref().allocator() }
|
unsafe { self.vec.as_ref().allocator() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Keep unyielded elements in the source `Vec`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(drain_keep_rest)]
|
||||||
|
///
|
||||||
|
/// let mut vec = vec!['a', 'b', 'c'];
|
||||||
|
/// let mut drain = vec.drain(..);
|
||||||
|
///
|
||||||
|
/// assert_eq!(drain.next().unwrap(), 'a');
|
||||||
|
///
|
||||||
|
/// // This call keeps 'b' and 'c' in the vec.
|
||||||
|
/// drain.keep_rest();
|
||||||
|
///
|
||||||
|
/// // If we wouldn't call `keep_rest()`,
|
||||||
|
/// // `vec` would be empty.
|
||||||
|
/// assert_eq!(vec, ['b', 'c']);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "drain_keep_rest", issue = "101122")]
|
||||||
|
pub fn keep_rest(self) {
|
||||||
|
// At this moment layout looks like this:
|
||||||
|
//
|
||||||
|
// [head] [yielded by next] [unyielded] [yielded by next_back] [tail]
|
||||||
|
// ^-- start \_________/-- unyielded_len \____/-- self.tail_len
|
||||||
|
// ^-- unyielded_ptr ^-- tail
|
||||||
|
//
|
||||||
|
// Normally `Drop` impl would drop [unyielded] and then move [tail] to the `start`.
|
||||||
|
// Here we want to
|
||||||
|
// 1. Move [unyielded] to `start`
|
||||||
|
// 2. Move [tail] to a new start at `start + len(unyielded)`
|
||||||
|
// 3. Update length of the original vec to `len(head) + len(unyielded) + len(tail)`
|
||||||
|
// a. In case of ZST, this is the only thing we want to do
|
||||||
|
// 4. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
|
||||||
|
let mut this = ManuallyDrop::new(self);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let source_vec = this.vec.as_mut();
|
||||||
|
|
||||||
|
let start = source_vec.len();
|
||||||
|
let tail = this.tail_start;
|
||||||
|
|
||||||
|
let unyielded_len = this.iter.len();
|
||||||
|
let unyielded_ptr = this.iter.as_slice().as_ptr();
|
||||||
|
|
||||||
|
// ZSTs have no identity, so we don't need to move them around.
|
||||||
|
let needs_move = mem::size_of::<T>() != 0;
|
||||||
|
|
||||||
|
if needs_move {
|
||||||
|
let start_ptr = source_vec.as_mut_ptr().add(start);
|
||||||
|
|
||||||
|
// memmove back unyielded elements
|
||||||
|
if unyielded_ptr != start_ptr {
|
||||||
|
let src = unyielded_ptr;
|
||||||
|
let dst = start_ptr;
|
||||||
|
|
||||||
|
ptr::copy(src, dst, unyielded_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// memmove back untouched tail
|
||||||
|
if tail != (start + unyielded_len) {
|
||||||
|
let src = source_vec.as_ptr().add(tail);
|
||||||
|
let dst = start_ptr.add(unyielded_len);
|
||||||
|
ptr::copy(src, dst, this.tail_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
source_vec.set_len(start + unyielded_len + this.tail_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
|
#[stable(feature = "vec_drain_as_slice", since = "1.46.0")]
|
||||||
@ -133,7 +204,7 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
|
|||||||
|
|
||||||
let mut vec = self.vec;
|
let mut vec = self.vec;
|
||||||
|
|
||||||
if mem::size_of::<T>() == 0 {
|
if T::IS_ZST {
|
||||||
// ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
|
// ZSTs have no identity, so we don't need to move them around, we only need to drop the correct amount.
|
||||||
// this can be achieved by manipulating the Vec length instead of moving values out from `iter`.
|
// this can be achieved by manipulating the Vec length instead of moving values out from `iter`.
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -154,9 +225,9 @@ impl<T, A: Allocator> Drop for Drain<'_, T, A> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// as_slice() must only be called when iter.len() is > 0 because
|
// as_slice() must only be called when iter.len() is > 0 because
|
||||||
// vec::Splice modifies vec::Drain fields and may grow the vec which would invalidate
|
// it also gets touched by vec::Splice which may turn it into a dangling pointer
|
||||||
// the iterator's internal pointers. Creating a reference to deallocated memory
|
// which would make it and the vec pointer point to different allocations which would
|
||||||
// is invalid even when it is zero-length
|
// lead to invalid pointer arithmetic below.
|
||||||
let drop_ptr = iter.as_slice().as_ptr();
|
let drop_ptr = iter.as_slice().as_ptr();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
|
||||||
use crate::alloc::{Allocator, Global};
|
use crate::alloc::{Allocator, Global};
|
||||||
use core::ptr::{self};
|
use core::mem::{self, ManuallyDrop};
|
||||||
use core::slice::{self};
|
use core::ptr;
|
||||||
|
use core::slice;
|
||||||
|
|
||||||
use super::Vec;
|
use super::Vec;
|
||||||
|
|
||||||
@ -56,6 +57,61 @@ where
|
|||||||
pub fn allocator(&self) -> &A {
|
pub fn allocator(&self) -> &A {
|
||||||
self.vec.allocator()
|
self.vec.allocator()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Keep unyielded elements in the source `Vec`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(drain_filter)]
|
||||||
|
/// #![feature(drain_keep_rest)]
|
||||||
|
///
|
||||||
|
/// let mut vec = vec!['a', 'b', 'c'];
|
||||||
|
/// let mut drain = vec.drain_filter(|_| true);
|
||||||
|
///
|
||||||
|
/// assert_eq!(drain.next().unwrap(), 'a');
|
||||||
|
///
|
||||||
|
/// // This call keeps 'b' and 'c' in the vec.
|
||||||
|
/// drain.keep_rest();
|
||||||
|
///
|
||||||
|
/// // If we wouldn't call `keep_rest()`,
|
||||||
|
/// // `vec` would be empty.
|
||||||
|
/// assert_eq!(vec, ['b', 'c']);
|
||||||
|
/// ```
|
||||||
|
#[unstable(feature = "drain_keep_rest", issue = "101122")]
|
||||||
|
pub fn keep_rest(self) {
|
||||||
|
// At this moment layout looks like this:
|
||||||
|
//
|
||||||
|
// _____________________/-- old_len
|
||||||
|
// / \
|
||||||
|
// [kept] [yielded] [tail]
|
||||||
|
// \_______/ ^-- idx
|
||||||
|
// \-- del
|
||||||
|
//
|
||||||
|
// Normally `Drop` impl would drop [tail] (via .for_each(drop), ie still calling `pred`)
|
||||||
|
//
|
||||||
|
// 1. Move [tail] after [kept]
|
||||||
|
// 2. Update length of the original vec to `old_len - del`
|
||||||
|
// a. In case of ZST, this is the only thing we want to do
|
||||||
|
// 3. Do *not* drop self, as everything is put in a consistent state already, there is nothing to do
|
||||||
|
let mut this = ManuallyDrop::new(self);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// ZSTs have no identity, so we don't need to move them around.
|
||||||
|
let needs_move = mem::size_of::<T>() != 0;
|
||||||
|
|
||||||
|
if needs_move && this.idx < this.old_len && this.del > 0 {
|
||||||
|
let ptr = this.vec.as_mut_ptr();
|
||||||
|
let src = ptr.add(this.idx);
|
||||||
|
let dst = src.sub(this.del);
|
||||||
|
let tail_len = this.old_len - this.idx;
|
||||||
|
src.copy_to(dst, tail_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_len = this.old_len - this.del;
|
||||||
|
this.vec.set_len(new_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
||||||
|
@ -3,14 +3,16 @@
|
|||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
use super::AsVecIntoIter;
|
use super::AsVecIntoIter;
|
||||||
use crate::alloc::{Allocator, Global};
|
use crate::alloc::{Allocator, Global};
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
use crate::collections::VecDeque;
|
||||||
use crate::raw_vec::RawVec;
|
use crate::raw_vec::RawVec;
|
||||||
|
use core::array;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::intrinsics::arith_offset;
|
|
||||||
use core::iter::{
|
use core::iter::{
|
||||||
FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce,
|
FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccessNoCoerce,
|
||||||
};
|
};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::mem::{self, ManuallyDrop};
|
use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
use core::ptr::{self, NonNull};
|
use core::ptr::{self, NonNull};
|
||||||
@ -40,7 +42,9 @@ pub struct IntoIter<
|
|||||||
// to avoid dropping the allocator twice we need to wrap it into ManuallyDrop
|
// to avoid dropping the allocator twice we need to wrap it into ManuallyDrop
|
||||||
pub(super) alloc: ManuallyDrop<A>,
|
pub(super) alloc: ManuallyDrop<A>,
|
||||||
pub(super) ptr: *const T,
|
pub(super) ptr: *const T,
|
||||||
pub(super) end: *const T,
|
pub(super) end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
|
||||||
|
// ptr == end is a quick test for the Iterator being empty, that works
|
||||||
|
// for both ZST and non-ZST.
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "vec_intoiter_debug", since = "1.13.0")]
|
#[stable(feature = "vec_intoiter_debug", since = "1.13.0")]
|
||||||
@ -97,13 +101,16 @@ impl<T, A: Allocator> IntoIter<T, A> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Drops remaining elements and relinquishes the backing allocation.
|
/// Drops remaining elements and relinquishes the backing allocation.
|
||||||
|
/// This method guarantees it won't panic before relinquishing
|
||||||
|
/// the backing allocation.
|
||||||
///
|
///
|
||||||
/// This is roughly equivalent to the following, but more efficient
|
/// This is roughly equivalent to the following, but more efficient
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # let mut into_iter = Vec::<u8>::with_capacity(10).into_iter();
|
/// # let mut into_iter = Vec::<u8>::with_capacity(10).into_iter();
|
||||||
|
/// let mut into_iter = std::mem::replace(&mut into_iter, Vec::new().into_iter());
|
||||||
/// (&mut into_iter).for_each(core::mem::drop);
|
/// (&mut into_iter).for_each(core::mem::drop);
|
||||||
/// unsafe { core::ptr::write(&mut into_iter, Vec::new().into_iter()); }
|
/// std::mem::forget(into_iter);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// This method is used by in-place iteration, refer to the vec::in_place_collect
|
/// This method is used by in-place iteration, refer to the vec::in_place_collect
|
||||||
@ -120,15 +127,45 @@ impl<T, A: Allocator> IntoIter<T, A> {
|
|||||||
self.ptr = self.buf.as_ptr();
|
self.ptr = self.buf.as_ptr();
|
||||||
self.end = self.buf.as_ptr();
|
self.end = self.buf.as_ptr();
|
||||||
|
|
||||||
|
// Dropping the remaining elements can panic, so this needs to be
|
||||||
|
// done only after updating the other fields.
|
||||||
unsafe {
|
unsafe {
|
||||||
ptr::drop_in_place(remaining);
|
ptr::drop_in_place(remaining);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed.
|
/// Forgets to Drop the remaining elements while still allowing the backing allocation to be freed.
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) fn forget_remaining_elements(&mut self) {
|
pub(crate) fn forget_remaining_elements(&mut self) {
|
||||||
self.ptr = self.end;
|
// For th ZST case, it is crucial that we mutate `end` here, not `ptr`.
|
||||||
|
// `ptr` must stay aligned, while `end` may be unaligned.
|
||||||
|
self.end = self.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn into_vecdeque(self) -> VecDeque<T, A> {
|
||||||
|
// Keep our `Drop` impl from dropping the elements and the allocator
|
||||||
|
let mut this = ManuallyDrop::new(self);
|
||||||
|
|
||||||
|
// SAFETY: This allocation originally came from a `Vec`, so it passes
|
||||||
|
// all those checks. We have `this.buf` ≤ `this.ptr` ≤ `this.end`,
|
||||||
|
// so the `sub_ptr`s below cannot wrap, and will produce a well-formed
|
||||||
|
// range. `end` ≤ `buf + cap`, so the range will be in-bounds.
|
||||||
|
// Taking `alloc` is ok because nothing else is going to look at it,
|
||||||
|
// since our `Drop` impl isn't going to run so there's no more code.
|
||||||
|
unsafe {
|
||||||
|
let buf = this.buf.as_ptr();
|
||||||
|
let initialized = if T::IS_ZST {
|
||||||
|
// All the pointers are the same for ZSTs, so it's fine to
|
||||||
|
// say that they're all at the beginning of the "allocation".
|
||||||
|
0..this.len()
|
||||||
|
} else {
|
||||||
|
this.ptr.sub_ptr(buf)..this.end.sub_ptr(buf)
|
||||||
|
};
|
||||||
|
let cap = this.cap;
|
||||||
|
let alloc = ManuallyDrop::take(&mut this.alloc);
|
||||||
|
VecDeque::from_contiguous_raw_parts_in(buf, initialized, cap, alloc)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,19 +187,18 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<T> {
|
fn next(&mut self) -> Option<T> {
|
||||||
if self.ptr as *const _ == self.end {
|
if self.ptr == self.end {
|
||||||
None
|
None
|
||||||
} else if mem::size_of::<T>() == 0 {
|
} else if T::IS_ZST {
|
||||||
// purposefully don't use 'ptr.offset' because for
|
// `ptr` has to stay where it is to remain aligned, so we reduce the length by 1 by
|
||||||
// vectors with 0-size elements this would return the
|
// reducing the `end`.
|
||||||
// same pointer.
|
self.end = self.end.wrapping_byte_sub(1);
|
||||||
self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T };
|
|
||||||
|
|
||||||
// Make up a value of this ZST.
|
// Make up a value of this ZST.
|
||||||
Some(unsafe { mem::zeroed() })
|
Some(unsafe { mem::zeroed() })
|
||||||
} else {
|
} else {
|
||||||
let old = self.ptr;
|
let old = self.ptr;
|
||||||
self.ptr = unsafe { self.ptr.offset(1) };
|
self.ptr = unsafe { self.ptr.add(1) };
|
||||||
|
|
||||||
Some(unsafe { ptr::read(old) })
|
Some(unsafe { ptr::read(old) })
|
||||||
}
|
}
|
||||||
@ -170,7 +206,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
let exact = if mem::size_of::<T>() == 0 {
|
let exact = if T::IS_ZST {
|
||||||
self.end.addr().wrapping_sub(self.ptr.addr())
|
self.end.addr().wrapping_sub(self.ptr.addr())
|
||||||
} else {
|
} else {
|
||||||
unsafe { self.end.sub_ptr(self.ptr) }
|
unsafe { self.end.sub_ptr(self.ptr) }
|
||||||
@ -182,11 +218,9 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
|
|||||||
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
fn advance_by(&mut self, n: usize) -> Result<(), usize> {
|
||||||
let step_size = self.len().min(n);
|
let step_size = self.len().min(n);
|
||||||
let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size);
|
let to_drop = ptr::slice_from_raw_parts_mut(self.ptr as *mut T, step_size);
|
||||||
if mem::size_of::<T>() == 0 {
|
if T::IS_ZST {
|
||||||
// SAFETY: due to unchecked casts of unsigned amounts to signed offsets the wraparound
|
// See `next` for why we sub `end` here.
|
||||||
// effectively results in unsigned pointers representing positions 0..usize::MAX,
|
self.end = self.end.wrapping_byte_sub(step_size);
|
||||||
// which is valid for ZSTs.
|
|
||||||
self.ptr = unsafe { arith_offset(self.ptr as *const i8, step_size as isize) as *mut T }
|
|
||||||
} else {
|
} else {
|
||||||
// SAFETY: the min() above ensures that step_size is in bounds
|
// SAFETY: the min() above ensures that step_size is in bounds
|
||||||
self.ptr = unsafe { self.ptr.add(step_size) };
|
self.ptr = unsafe { self.ptr.add(step_size) };
|
||||||
@ -206,6 +240,43 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
|
|||||||
self.len()
|
self.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next_chunk<const N: usize>(&mut self) -> Result<[T; N], core::array::IntoIter<T, N>> {
|
||||||
|
let mut raw_ary = MaybeUninit::uninit_array();
|
||||||
|
|
||||||
|
let len = self.len();
|
||||||
|
|
||||||
|
if T::IS_ZST {
|
||||||
|
if len < N {
|
||||||
|
self.forget_remaining_elements();
|
||||||
|
// Safety: ZSTs can be conjured ex nihilo, only the amount has to be correct
|
||||||
|
return Err(unsafe { array::IntoIter::new_unchecked(raw_ary, 0..len) });
|
||||||
|
}
|
||||||
|
|
||||||
|
self.end = self.end.wrapping_byte_sub(N);
|
||||||
|
// Safety: ditto
|
||||||
|
return Ok(unsafe { raw_ary.transpose().assume_init() });
|
||||||
|
}
|
||||||
|
|
||||||
|
if len < N {
|
||||||
|
// Safety: `len` indicates that this many elements are available and we just checked that
|
||||||
|
// it fits into the array.
|
||||||
|
unsafe {
|
||||||
|
ptr::copy_nonoverlapping(self.ptr, raw_ary.as_mut_ptr() as *mut T, len);
|
||||||
|
self.forget_remaining_elements();
|
||||||
|
return Err(array::IntoIter::new_unchecked(raw_ary, 0..len));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safety: `len` is larger than the array size. Copy a fixed amount here to fully initialize
|
||||||
|
// the array.
|
||||||
|
return unsafe {
|
||||||
|
ptr::copy_nonoverlapping(self.ptr, raw_ary.as_mut_ptr() as *mut T, N);
|
||||||
|
self.ptr = self.ptr.add(N);
|
||||||
|
Ok(raw_ary.transpose().assume_init())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
|
unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
|
||||||
where
|
where
|
||||||
Self: TrustedRandomAccessNoCoerce,
|
Self: TrustedRandomAccessNoCoerce,
|
||||||
@ -219,7 +290,7 @@ impl<T, A: Allocator> Iterator for IntoIter<T, A> {
|
|||||||
// that `T: Copy` so reading elements from the buffer doesn't invalidate
|
// that `T: Copy` so reading elements from the buffer doesn't invalidate
|
||||||
// them for `Drop`.
|
// them for `Drop`.
|
||||||
unsafe {
|
unsafe {
|
||||||
if mem::size_of::<T>() == 0 { mem::zeroed() } else { ptr::read(self.ptr.add(i)) }
|
if T::IS_ZST { mem::zeroed() } else { ptr::read(self.ptr.add(i)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,14 +301,14 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
|
|||||||
fn next_back(&mut self) -> Option<T> {
|
fn next_back(&mut self) -> Option<T> {
|
||||||
if self.end == self.ptr {
|
if self.end == self.ptr {
|
||||||
None
|
None
|
||||||
} else if mem::size_of::<T>() == 0 {
|
} else if T::IS_ZST {
|
||||||
// See above for why 'ptr.offset' isn't used
|
// See above for why 'ptr.offset' isn't used
|
||||||
self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T };
|
self.end = self.end.wrapping_byte_sub(1);
|
||||||
|
|
||||||
// Make up a value of this ZST.
|
// Make up a value of this ZST.
|
||||||
Some(unsafe { mem::zeroed() })
|
Some(unsafe { mem::zeroed() })
|
||||||
} else {
|
} else {
|
||||||
self.end = unsafe { self.end.offset(-1) };
|
self.end = unsafe { self.end.sub(1) };
|
||||||
|
|
||||||
Some(unsafe { ptr::read(self.end) })
|
Some(unsafe { ptr::read(self.end) })
|
||||||
}
|
}
|
||||||
@ -246,14 +317,12 @@ impl<T, A: Allocator> DoubleEndedIterator for IntoIter<T, A> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
fn advance_back_by(&mut self, n: usize) -> Result<(), usize> {
|
||||||
let step_size = self.len().min(n);
|
let step_size = self.len().min(n);
|
||||||
if mem::size_of::<T>() == 0 {
|
if T::IS_ZST {
|
||||||
// SAFETY: same as for advance_by()
|
// SAFETY: same as for advance_by()
|
||||||
self.end = unsafe {
|
self.end = self.end.wrapping_byte_sub(step_size);
|
||||||
arith_offset(self.end as *const i8, step_size.wrapping_neg() as isize) as *mut T
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// SAFETY: same as for advance_by()
|
// SAFETY: same as for advance_by()
|
||||||
self.end = unsafe { self.end.offset(step_size.wrapping_neg() as isize) };
|
self.end = unsafe { self.end.sub(step_size) };
|
||||||
}
|
}
|
||||||
let to_drop = ptr::slice_from_raw_parts_mut(self.end as *mut T, step_size);
|
let to_drop = ptr::slice_from_raw_parts_mut(self.end as *mut T, step_size);
|
||||||
// SAFETY: same as for advance_by()
|
// SAFETY: same as for advance_by()
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
|
||||||
|
use core::num::{Saturating, Wrapping};
|
||||||
|
|
||||||
use crate::boxed::Box;
|
use crate::boxed::Box;
|
||||||
|
|
||||||
#[rustc_specialization_trait]
|
#[rustc_specialization_trait]
|
||||||
pub(super) unsafe trait IsZero {
|
pub(super) unsafe trait IsZero {
|
||||||
/// Whether this value's representation is all zeros
|
/// Whether this value's representation is all zeros,
|
||||||
|
/// or can be represented with all zeroes.
|
||||||
fn is_zero(&self) -> bool;
|
fn is_zero(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,12 +22,14 @@ macro_rules! impl_is_zero {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl_is_zero!(i8, |x| x == 0); // It is needed to impl for arrays and tuples of i8.
|
||||||
impl_is_zero!(i16, |x| x == 0);
|
impl_is_zero!(i16, |x| x == 0);
|
||||||
impl_is_zero!(i32, |x| x == 0);
|
impl_is_zero!(i32, |x| x == 0);
|
||||||
impl_is_zero!(i64, |x| x == 0);
|
impl_is_zero!(i64, |x| x == 0);
|
||||||
impl_is_zero!(i128, |x| x == 0);
|
impl_is_zero!(i128, |x| x == 0);
|
||||||
impl_is_zero!(isize, |x| x == 0);
|
impl_is_zero!(isize, |x| x == 0);
|
||||||
|
|
||||||
|
impl_is_zero!(u8, |x| x == 0); // It is needed to impl for arrays and tuples of u8.
|
||||||
impl_is_zero!(u16, |x| x == 0);
|
impl_is_zero!(u16, |x| x == 0);
|
||||||
impl_is_zero!(u32, |x| x == 0);
|
impl_is_zero!(u32, |x| x == 0);
|
||||||
impl_is_zero!(u64, |x| x == 0);
|
impl_is_zero!(u64, |x| x == 0);
|
||||||
@ -55,16 +60,42 @@ unsafe impl<T: IsZero, const N: usize> IsZero for [T; N] {
|
|||||||
#[inline]
|
#[inline]
|
||||||
fn is_zero(&self) -> bool {
|
fn is_zero(&self) -> bool {
|
||||||
// Because this is generated as a runtime check, it's not obvious that
|
// Because this is generated as a runtime check, it's not obvious that
|
||||||
// it's worth doing if the array is really long. The threshold here
|
// it's worth doing if the array is really long. The threshold here
|
||||||
// is largely arbitrary, but was picked because as of 2022-05-01 LLVM
|
// is largely arbitrary, but was picked because as of 2022-07-01 LLVM
|
||||||
// can const-fold the check in `vec![[0; 32]; n]` but not in
|
// fails to const-fold the check in `vec![[1; 32]; n]`
|
||||||
// `vec![[0; 64]; n]`: https://godbolt.org/z/WTzjzfs5b
|
// See https://github.com/rust-lang/rust/pull/97581#issuecomment-1166628022
|
||||||
// Feel free to tweak if you have better evidence.
|
// Feel free to tweak if you have better evidence.
|
||||||
|
|
||||||
N <= 32 && self.iter().all(IsZero::is_zero)
|
N <= 16 && self.iter().all(IsZero::is_zero)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is recursive macro.
|
||||||
|
macro_rules! impl_for_tuples {
|
||||||
|
// Stopper
|
||||||
|
() => {
|
||||||
|
// No use for implementing for empty tuple because it is ZST.
|
||||||
|
};
|
||||||
|
($first_arg:ident $(,$rest:ident)*) => {
|
||||||
|
unsafe impl <$first_arg: IsZero, $($rest: IsZero,)*> IsZero for ($first_arg, $($rest,)*){
|
||||||
|
#[inline]
|
||||||
|
fn is_zero(&self) -> bool{
|
||||||
|
// Destructure tuple to N references
|
||||||
|
// Rust allows to hide generic params by local variable names.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
let ($first_arg, $($rest,)*) = self;
|
||||||
|
|
||||||
|
$first_arg.is_zero()
|
||||||
|
$( && $rest.is_zero() )*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_for_tuples!($($rest),*);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_for_tuples!(A, B, C, D, E, F, G, H);
|
||||||
|
|
||||||
// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
|
// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
|
||||||
// For fat pointers, the bytes that would be the pointer metadata in the `Some`
|
// For fat pointers, the bytes that would be the pointer metadata in the `Some`
|
||||||
// variant are padding in the `None` variant, so ignoring them and
|
// variant are padding in the `None` variant, so ignoring them and
|
||||||
@ -118,3 +149,56 @@ impl_is_zero_option_of_nonzero!(
|
|||||||
NonZeroUsize,
|
NonZeroUsize,
|
||||||
NonZeroIsize,
|
NonZeroIsize,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
macro_rules! impl_is_zero_option_of_num {
|
||||||
|
($($t:ty,)+) => {$(
|
||||||
|
unsafe impl IsZero for Option<$t> {
|
||||||
|
#[inline]
|
||||||
|
fn is_zero(&self) -> bool {
|
||||||
|
const {
|
||||||
|
let none: Self = unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
|
||||||
|
assert!(none.is_none());
|
||||||
|
}
|
||||||
|
self.is_none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_is_zero_option_of_num!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize,);
|
||||||
|
|
||||||
|
unsafe impl<T: IsZero> IsZero for Wrapping<T> {
|
||||||
|
#[inline]
|
||||||
|
fn is_zero(&self) -> bool {
|
||||||
|
self.0.is_zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T: IsZero> IsZero for Saturating<T> {
|
||||||
|
#[inline]
|
||||||
|
fn is_zero(&self) -> bool {
|
||||||
|
self.0.is_zero()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_for_optional_bool {
|
||||||
|
($($t:ty,)+) => {$(
|
||||||
|
unsafe impl IsZero for $t {
|
||||||
|
#[inline]
|
||||||
|
fn is_zero(&self) -> bool {
|
||||||
|
// SAFETY: This is *not* a stable layout guarantee, but
|
||||||
|
// inside `core` we're allowed to rely on the current rustc
|
||||||
|
// behaviour that options of bools will be one byte with
|
||||||
|
// no padding, so long as they're nested less than 254 deep.
|
||||||
|
let raw: u8 = unsafe { core::mem::transmute(*self) };
|
||||||
|
raw == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)+};
|
||||||
|
}
|
||||||
|
impl_for_optional_bool! {
|
||||||
|
Option<bool>,
|
||||||
|
Option<Option<bool>>,
|
||||||
|
Option<Option<Option<bool>>>,
|
||||||
|
// Could go further, but not worth the metadata overhead
|
||||||
|
}
|
||||||
|
@ -61,12 +61,12 @@ use core::cmp::Ordering;
|
|||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::hash::{Hash, Hasher};
|
use core::hash::{Hash, Hasher};
|
||||||
use core::intrinsics::{arith_offset, assume};
|
use core::intrinsics::assume;
|
||||||
use core::iter;
|
use core::iter;
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
use core::iter::FromIterator;
|
use core::iter::FromIterator;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::mem::{self, ManuallyDrop, MaybeUninit};
|
use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties};
|
||||||
use core::ops::{self, Index, IndexMut, Range, RangeBounds};
|
use core::ops::{self, Index, IndexMut, Range, RangeBounds};
|
||||||
use core::ptr::{self, NonNull};
|
use core::ptr::{self, NonNull};
|
||||||
use core::slice::{self, SliceIndex};
|
use core::slice::{self, SliceIndex};
|
||||||
@ -75,7 +75,7 @@ use crate::alloc::{Allocator, Global};
|
|||||||
#[cfg(not(no_borrow))]
|
#[cfg(not(no_borrow))]
|
||||||
use crate::borrow::{Cow, ToOwned};
|
use crate::borrow::{Cow, ToOwned};
|
||||||
use crate::boxed::Box;
|
use crate::boxed::Box;
|
||||||
use crate::collections::TryReserveError;
|
use crate::collections::{TryReserveError, TryReserveErrorKind};
|
||||||
use crate::raw_vec::RawVec;
|
use crate::raw_vec::RawVec;
|
||||||
|
|
||||||
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
#[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")]
|
||||||
@ -127,7 +127,7 @@ use self::set_len_on_drop::SetLenOnDrop;
|
|||||||
mod set_len_on_drop;
|
mod set_len_on_drop;
|
||||||
|
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
use self::in_place_drop::InPlaceDrop;
|
use self::in_place_drop::{InPlaceDrop, InPlaceDstBufDrop};
|
||||||
|
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
mod in_place_drop;
|
mod in_place_drop;
|
||||||
@ -169,7 +169,7 @@ mod spec_extend;
|
|||||||
/// vec[0] = 7;
|
/// vec[0] = 7;
|
||||||
/// assert_eq!(vec[0], 7);
|
/// assert_eq!(vec[0], 7);
|
||||||
///
|
///
|
||||||
/// vec.extend([1, 2, 3].iter().copied());
|
/// vec.extend([1, 2, 3]);
|
||||||
///
|
///
|
||||||
/// for x in &vec {
|
/// for x in &vec {
|
||||||
/// println!("{x}");
|
/// println!("{x}");
|
||||||
@ -428,17 +428,25 @@ impl<T> Vec<T> {
|
|||||||
Vec { buf: RawVec::NEW, len: 0 }
|
Vec { buf: RawVec::NEW, len: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new, empty `Vec<T>` with the specified capacity.
|
/// Constructs a new, empty `Vec<T>` with at least the specified capacity.
|
||||||
///
|
///
|
||||||
/// The vector will be able to hold exactly `capacity` elements without
|
/// The vector will be able to hold at least `capacity` elements without
|
||||||
/// reallocating. If `capacity` is 0, the vector will not allocate.
|
/// reallocating. This method is allowed to allocate for more elements than
|
||||||
|
/// `capacity`. If `capacity` is 0, the vector will not allocate.
|
||||||
///
|
///
|
||||||
/// It is important to note that although the returned vector has the
|
/// It is important to note that although the returned vector has the
|
||||||
/// *capacity* specified, the vector will have a zero *length*. For an
|
/// minimum *capacity* specified, the vector will have a zero *length*. For
|
||||||
/// explanation of the difference between length and capacity, see
|
/// an explanation of the difference between length and capacity, see
|
||||||
/// *[Capacity and reallocation]*.
|
/// *[Capacity and reallocation]*.
|
||||||
///
|
///
|
||||||
|
/// If it is important to know the exact allocated capacity of a `Vec`,
|
||||||
|
/// always use the [`capacity`] method after construction.
|
||||||
|
///
|
||||||
|
/// For `Vec<T>` where `T` is a zero-sized type, there will be no allocation
|
||||||
|
/// and the capacity will always be `usize::MAX`.
|
||||||
|
///
|
||||||
/// [Capacity and reallocation]: #capacity-and-reallocation
|
/// [Capacity and reallocation]: #capacity-and-reallocation
|
||||||
|
/// [`capacity`]: Vec::capacity
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
@ -451,19 +459,24 @@ impl<T> Vec<T> {
|
|||||||
///
|
///
|
||||||
/// // The vector contains no items, even though it has capacity for more
|
/// // The vector contains no items, even though it has capacity for more
|
||||||
/// assert_eq!(vec.len(), 0);
|
/// assert_eq!(vec.len(), 0);
|
||||||
/// assert_eq!(vec.capacity(), 10);
|
/// assert!(vec.capacity() >= 10);
|
||||||
///
|
///
|
||||||
/// // These are all done without reallocating...
|
/// // These are all done without reallocating...
|
||||||
/// for i in 0..10 {
|
/// for i in 0..10 {
|
||||||
/// vec.push(i);
|
/// vec.push(i);
|
||||||
/// }
|
/// }
|
||||||
/// assert_eq!(vec.len(), 10);
|
/// assert_eq!(vec.len(), 10);
|
||||||
/// assert_eq!(vec.capacity(), 10);
|
/// assert!(vec.capacity() >= 10);
|
||||||
///
|
///
|
||||||
/// // ...but this may make the vector reallocate
|
/// // ...but this may make the vector reallocate
|
||||||
/// vec.push(11);
|
/// vec.push(11);
|
||||||
/// assert_eq!(vec.len(), 11);
|
/// assert_eq!(vec.len(), 11);
|
||||||
/// assert!(vec.capacity() >= 11);
|
/// assert!(vec.capacity() >= 11);
|
||||||
|
///
|
||||||
|
/// // A vector of a zero-sized type will always over-allocate, since no
|
||||||
|
/// // allocation is necessary
|
||||||
|
/// let vec_units = Vec::<()>::with_capacity(10);
|
||||||
|
/// assert_eq!(vec_units.capacity(), usize::MAX);
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -473,17 +486,25 @@ impl<T> Vec<T> {
|
|||||||
Self::with_capacity_in(capacity, Global)
|
Self::with_capacity_in(capacity, Global)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to construct a new, empty `Vec<T>` with the specified capacity.
|
/// Tries to construct a new, empty `Vec<T>` with at least the specified capacity.
|
||||||
///
|
///
|
||||||
/// The vector will be able to hold exactly `capacity` elements without
|
/// The vector will be able to hold at least `capacity` elements without
|
||||||
/// reallocating. If `capacity` is 0, the vector will not allocate.
|
/// reallocating. This method is allowed to allocate for more elements than
|
||||||
|
/// `capacity`. If `capacity` is 0, the vector will not allocate.
|
||||||
///
|
///
|
||||||
/// It is important to note that although the returned vector has the
|
/// It is important to note that although the returned vector has the
|
||||||
/// *capacity* specified, the vector will have a zero *length*. For an
|
/// minimum *capacity* specified, the vector will have a zero *length*. For
|
||||||
/// explanation of the difference between length and capacity, see
|
/// an explanation of the difference between length and capacity, see
|
||||||
/// *[Capacity and reallocation]*.
|
/// *[Capacity and reallocation]*.
|
||||||
///
|
///
|
||||||
|
/// If it is important to know the exact allocated capacity of a `Vec`,
|
||||||
|
/// always use the [`capacity`] method after construction.
|
||||||
|
///
|
||||||
|
/// For `Vec<T>` where `T` is a zero-sized type, there will be no allocation
|
||||||
|
/// and the capacity will always be `usize::MAX`.
|
||||||
|
///
|
||||||
/// [Capacity and reallocation]: #capacity-and-reallocation
|
/// [Capacity and reallocation]: #capacity-and-reallocation
|
||||||
|
/// [`capacity`]: Vec::capacity
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@ -492,14 +513,14 @@ impl<T> Vec<T> {
|
|||||||
///
|
///
|
||||||
/// // The vector contains no items, even though it has capacity for more
|
/// // The vector contains no items, even though it has capacity for more
|
||||||
/// assert_eq!(vec.len(), 0);
|
/// assert_eq!(vec.len(), 0);
|
||||||
/// assert_eq!(vec.capacity(), 10);
|
/// assert!(vec.capacity() >= 10);
|
||||||
///
|
///
|
||||||
/// // These are all done without reallocating...
|
/// // These are all done without reallocating...
|
||||||
/// for i in 0..10 {
|
/// for i in 0..10 {
|
||||||
/// vec.push(i);
|
/// vec.push(i);
|
||||||
/// }
|
/// }
|
||||||
/// assert_eq!(vec.len(), 10);
|
/// assert_eq!(vec.len(), 10);
|
||||||
/// assert_eq!(vec.capacity(), 10);
|
/// assert!(vec.capacity() >= 10);
|
||||||
///
|
///
|
||||||
/// // ...but this may make the vector reallocate
|
/// // ...but this may make the vector reallocate
|
||||||
/// vec.push(11);
|
/// vec.push(11);
|
||||||
@ -508,6 +529,11 @@ impl<T> Vec<T> {
|
|||||||
///
|
///
|
||||||
/// let mut result = Vec::try_with_capacity(usize::MAX);
|
/// let mut result = Vec::try_with_capacity(usize::MAX);
|
||||||
/// assert!(result.is_err());
|
/// assert!(result.is_err());
|
||||||
|
///
|
||||||
|
/// // A vector of a zero-sized type will always over-allocate, since no
|
||||||
|
/// // allocation is necessary
|
||||||
|
/// let vec_units = Vec::<()>::try_with_capacity(10).unwrap();
|
||||||
|
/// assert_eq!(vec_units.capacity(), usize::MAX);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "kernel", since = "1.0.0")]
|
#[stable(feature = "kernel", since = "1.0.0")]
|
||||||
@ -515,15 +541,15 @@ impl<T> Vec<T> {
|
|||||||
Self::try_with_capacity_in(capacity, Global)
|
Self::try_with_capacity_in(capacity, Global)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `Vec<T>` directly from the raw components of another vector.
|
/// Creates a `Vec<T>` directly from a pointer, a capacity, and a length.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This is highly unsafe, due to the number of invariants that aren't
|
/// This is highly unsafe, due to the number of invariants that aren't
|
||||||
/// checked:
|
/// checked:
|
||||||
///
|
///
|
||||||
/// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
|
/// * `ptr` must have been allocated using the global allocator, such as via
|
||||||
/// (at least, it's highly likely to be incorrect if it wasn't).
|
/// the [`alloc::alloc`] function.
|
||||||
/// * `T` needs to have the same alignment as what `ptr` was allocated with.
|
/// * `T` needs to have the same alignment as what `ptr` was allocated with.
|
||||||
/// (`T` having a less strict alignment is not sufficient, the alignment really
|
/// (`T` having a less strict alignment is not sufficient, the alignment really
|
||||||
/// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
|
/// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
|
||||||
@ -532,6 +558,14 @@ impl<T> Vec<T> {
|
|||||||
/// to be the same size as the pointer was allocated with. (Because similar to
|
/// to be the same size as the pointer was allocated with. (Because similar to
|
||||||
/// alignment, [`dealloc`] must be called with the same layout `size`.)
|
/// alignment, [`dealloc`] must be called with the same layout `size`.)
|
||||||
/// * `length` needs to be less than or equal to `capacity`.
|
/// * `length` needs to be less than or equal to `capacity`.
|
||||||
|
/// * The first `length` values must be properly initialized values of type `T`.
|
||||||
|
/// * `capacity` needs to be the capacity that the pointer was allocated with.
|
||||||
|
/// * The allocated size in bytes must be no larger than `isize::MAX`.
|
||||||
|
/// See the safety documentation of [`pointer::offset`].
|
||||||
|
///
|
||||||
|
/// These requirements are always upheld by any `ptr` that has been allocated
|
||||||
|
/// via `Vec<T>`. Other allocation sources are allowed if the invariants are
|
||||||
|
/// upheld.
|
||||||
///
|
///
|
||||||
/// Violating these may cause problems like corrupting the allocator's
|
/// Violating these may cause problems like corrupting the allocator's
|
||||||
/// internal data structures. For example it is normally **not** safe
|
/// internal data structures. For example it is normally **not** safe
|
||||||
@ -552,6 +586,7 @@ impl<T> Vec<T> {
|
|||||||
/// function.
|
/// function.
|
||||||
///
|
///
|
||||||
/// [`String`]: crate::string::String
|
/// [`String`]: crate::string::String
|
||||||
|
/// [`alloc::alloc`]: crate::alloc::alloc
|
||||||
/// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
|
/// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
@ -574,8 +609,8 @@ impl<T> Vec<T> {
|
|||||||
///
|
///
|
||||||
/// unsafe {
|
/// unsafe {
|
||||||
/// // Overwrite memory with 4, 5, 6
|
/// // Overwrite memory with 4, 5, 6
|
||||||
/// for i in 0..len as isize {
|
/// for i in 0..len {
|
||||||
/// ptr::write(p.offset(i), 4 + i);
|
/// ptr::write(p.add(i), 4 + i);
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// // Put everything back together into a Vec
|
/// // Put everything back together into a Vec
|
||||||
@ -583,6 +618,32 @@ impl<T> Vec<T> {
|
|||||||
/// assert_eq!(rebuilt, [4, 5, 6]);
|
/// assert_eq!(rebuilt, [4, 5, 6]);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// Using memory that was allocated elsewhere:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// #![feature(allocator_api)]
|
||||||
|
///
|
||||||
|
/// use std::alloc::{AllocError, Allocator, Global, Layout};
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let layout = Layout::array::<u32>(16).expect("overflow cannot happen");
|
||||||
|
///
|
||||||
|
/// let vec = unsafe {
|
||||||
|
/// let mem = match Global.allocate(layout) {
|
||||||
|
/// Ok(mem) => mem.cast::<u32>().as_ptr(),
|
||||||
|
/// Err(AllocError) => return,
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// mem.write(1_000_000);
|
||||||
|
///
|
||||||
|
/// Vec::from_raw_parts_in(mem, 1, 16, Global)
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// assert_eq!(vec, &[1_000_000]);
|
||||||
|
/// assert_eq!(vec.capacity(), 16);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
|
pub unsafe fn from_raw_parts(ptr: *mut T, length: usize, capacity: usize) -> Self {
|
||||||
@ -611,18 +672,26 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
Vec { buf: RawVec::new_in(alloc), len: 0 }
|
Vec { buf: RawVec::new_in(alloc), len: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new, empty `Vec<T, A>` with the specified capacity with the provided
|
/// Constructs a new, empty `Vec<T, A>` with at least the specified capacity
|
||||||
/// allocator.
|
/// with the provided allocator.
|
||||||
///
|
///
|
||||||
/// The vector will be able to hold exactly `capacity` elements without
|
/// The vector will be able to hold at least `capacity` elements without
|
||||||
/// reallocating. If `capacity` is 0, the vector will not allocate.
|
/// reallocating. This method is allowed to allocate for more elements than
|
||||||
|
/// `capacity`. If `capacity` is 0, the vector will not allocate.
|
||||||
///
|
///
|
||||||
/// It is important to note that although the returned vector has the
|
/// It is important to note that although the returned vector has the
|
||||||
/// *capacity* specified, the vector will have a zero *length*. For an
|
/// minimum *capacity* specified, the vector will have a zero *length*. For
|
||||||
/// explanation of the difference between length and capacity, see
|
/// an explanation of the difference between length and capacity, see
|
||||||
/// *[Capacity and reallocation]*.
|
/// *[Capacity and reallocation]*.
|
||||||
///
|
///
|
||||||
|
/// If it is important to know the exact allocated capacity of a `Vec`,
|
||||||
|
/// always use the [`capacity`] method after construction.
|
||||||
|
///
|
||||||
|
/// For `Vec<T, A>` where `T` is a zero-sized type, there will be no allocation
|
||||||
|
/// and the capacity will always be `usize::MAX`.
|
||||||
|
///
|
||||||
/// [Capacity and reallocation]: #capacity-and-reallocation
|
/// [Capacity and reallocation]: #capacity-and-reallocation
|
||||||
|
/// [`capacity`]: Vec::capacity
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
@ -652,6 +721,11 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
/// vec.push(11);
|
/// vec.push(11);
|
||||||
/// assert_eq!(vec.len(), 11);
|
/// assert_eq!(vec.len(), 11);
|
||||||
/// assert!(vec.capacity() >= 11);
|
/// assert!(vec.capacity() >= 11);
|
||||||
|
///
|
||||||
|
/// // A vector of a zero-sized type will always over-allocate, since no
|
||||||
|
/// // allocation is necessary
|
||||||
|
/// let vec_units = Vec::<(), System>::with_capacity_in(10, System);
|
||||||
|
/// assert_eq!(vec_units.capacity(), usize::MAX);
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -660,18 +734,26 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 }
|
Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to construct a new, empty `Vec<T, A>` with the specified capacity
|
/// Tries to construct a new, empty `Vec<T, A>` with at least the specified capacity
|
||||||
/// with the provided allocator.
|
/// with the provided allocator.
|
||||||
///
|
///
|
||||||
/// The vector will be able to hold exactly `capacity` elements without
|
/// The vector will be able to hold at least `capacity` elements without
|
||||||
/// reallocating. If `capacity` is 0, the vector will not allocate.
|
/// reallocating. This method is allowed to allocate for more elements than
|
||||||
|
/// `capacity`. If `capacity` is 0, the vector will not allocate.
|
||||||
///
|
///
|
||||||
/// It is important to note that although the returned vector has the
|
/// It is important to note that although the returned vector has the
|
||||||
/// *capacity* specified, the vector will have a zero *length*. For an
|
/// minimum *capacity* specified, the vector will have a zero *length*. For
|
||||||
/// explanation of the difference between length and capacity, see
|
/// an explanation of the difference between length and capacity, see
|
||||||
/// *[Capacity and reallocation]*.
|
/// *[Capacity and reallocation]*.
|
||||||
///
|
///
|
||||||
|
/// If it is important to know the exact allocated capacity of a `Vec`,
|
||||||
|
/// always use the [`capacity`] method after construction.
|
||||||
|
///
|
||||||
|
/// For `Vec<T, A>` where `T` is a zero-sized type, there will be no allocation
|
||||||
|
/// and the capacity will always be `usize::MAX`.
|
||||||
|
///
|
||||||
/// [Capacity and reallocation]: #capacity-and-reallocation
|
/// [Capacity and reallocation]: #capacity-and-reallocation
|
||||||
|
/// [`capacity`]: Vec::capacity
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@ -700,6 +782,11 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
///
|
///
|
||||||
/// let mut result = Vec::try_with_capacity_in(usize::MAX, System);
|
/// let mut result = Vec::try_with_capacity_in(usize::MAX, System);
|
||||||
/// assert!(result.is_err());
|
/// assert!(result.is_err());
|
||||||
|
///
|
||||||
|
/// // A vector of a zero-sized type will always over-allocate, since no
|
||||||
|
/// // allocation is necessary
|
||||||
|
/// let vec_units = Vec::<(), System>::try_with_capacity_in(10, System).unwrap();
|
||||||
|
/// assert_eq!(vec_units.capacity(), usize::MAX);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "kernel", since = "1.0.0")]
|
#[stable(feature = "kernel", since = "1.0.0")]
|
||||||
@ -707,21 +794,31 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
Ok(Vec { buf: RawVec::try_with_capacity_in(capacity, alloc)?, len: 0 })
|
Ok(Vec { buf: RawVec::try_with_capacity_in(capacity, alloc)?, len: 0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `Vec<T, A>` directly from the raw components of another vector.
|
/// Creates a `Vec<T, A>` directly from a pointer, a capacity, a length,
|
||||||
|
/// and an allocator.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This is highly unsafe, due to the number of invariants that aren't
|
/// This is highly unsafe, due to the number of invariants that aren't
|
||||||
/// checked:
|
/// checked:
|
||||||
///
|
///
|
||||||
/// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
|
/// * `ptr` must be [*currently allocated*] via the given allocator `alloc`.
|
||||||
/// (at least, it's highly likely to be incorrect if it wasn't).
|
/// * `T` needs to have the same alignment as what `ptr` was allocated with.
|
||||||
/// * `T` needs to have the same size and alignment as what `ptr` was allocated with.
|
|
||||||
/// (`T` having a less strict alignment is not sufficient, the alignment really
|
/// (`T` having a less strict alignment is not sufficient, the alignment really
|
||||||
/// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
|
/// needs to be equal to satisfy the [`dealloc`] requirement that memory must be
|
||||||
/// allocated and deallocated with the same layout.)
|
/// allocated and deallocated with the same layout.)
|
||||||
|
/// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs
|
||||||
|
/// to be the same size as the pointer was allocated with. (Because similar to
|
||||||
|
/// alignment, [`dealloc`] must be called with the same layout `size`.)
|
||||||
/// * `length` needs to be less than or equal to `capacity`.
|
/// * `length` needs to be less than or equal to `capacity`.
|
||||||
/// * `capacity` needs to be the capacity that the pointer was allocated with.
|
/// * The first `length` values must be properly initialized values of type `T`.
|
||||||
|
/// * `capacity` needs to [*fit*] the layout size that the pointer was allocated with.
|
||||||
|
/// * The allocated size in bytes must be no larger than `isize::MAX`.
|
||||||
|
/// See the safety documentation of [`pointer::offset`].
|
||||||
|
///
|
||||||
|
/// These requirements are always upheld by any `ptr` that has been allocated
|
||||||
|
/// via `Vec<T, A>`. Other allocation sources are allowed if the invariants are
|
||||||
|
/// upheld.
|
||||||
///
|
///
|
||||||
/// Violating these may cause problems like corrupting the allocator's
|
/// Violating these may cause problems like corrupting the allocator's
|
||||||
/// internal data structures. For example it is **not** safe
|
/// internal data structures. For example it is **not** safe
|
||||||
@ -739,6 +836,8 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
///
|
///
|
||||||
/// [`String`]: crate::string::String
|
/// [`String`]: crate::string::String
|
||||||
/// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
|
/// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
|
||||||
|
/// [*currently allocated*]: crate::alloc::Allocator#currently-allocated-memory
|
||||||
|
/// [*fit*]: crate::alloc::Allocator#memory-fitting
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@ -768,8 +867,8 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
///
|
///
|
||||||
/// unsafe {
|
/// unsafe {
|
||||||
/// // Overwrite memory with 4, 5, 6
|
/// // Overwrite memory with 4, 5, 6
|
||||||
/// for i in 0..len as isize {
|
/// for i in 0..len {
|
||||||
/// ptr::write(p.offset(i), 4 + i);
|
/// ptr::write(p.add(i), 4 + i);
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// // Put everything back together into a Vec
|
/// // Put everything back together into a Vec
|
||||||
@ -777,6 +876,29 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
/// assert_eq!(rebuilt, [4, 5, 6]);
|
/// assert_eq!(rebuilt, [4, 5, 6]);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// Using memory that was allocated elsewhere:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use std::alloc::{alloc, Layout};
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let layout = Layout::array::<u32>(16).expect("overflow cannot happen");
|
||||||
|
/// let vec = unsafe {
|
||||||
|
/// let mem = alloc(layout).cast::<u32>();
|
||||||
|
/// if mem.is_null() {
|
||||||
|
/// return;
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// mem.write(1_000_000);
|
||||||
|
///
|
||||||
|
/// Vec::from_raw_parts(mem, 1, 16)
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// assert_eq!(vec, &[1_000_000]);
|
||||||
|
/// assert_eq!(vec.capacity(), 16);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[unstable(feature = "allocator_api", issue = "32838")]
|
#[unstable(feature = "allocator_api", issue = "32838")]
|
||||||
pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self {
|
pub unsafe fn from_raw_parts_in(ptr: *mut T, length: usize, capacity: usize, alloc: A) -> Self {
|
||||||
@ -869,13 +991,14 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
(ptr, len, capacity, alloc)
|
(ptr, len, capacity, alloc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of elements the vector can hold without
|
/// Returns the total number of elements the vector can hold without
|
||||||
/// reallocating.
|
/// reallocating.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let vec: Vec<i32> = Vec::with_capacity(10);
|
/// let mut vec: Vec<i32> = Vec::with_capacity(10);
|
||||||
|
/// vec.push(42);
|
||||||
/// assert_eq!(vec.capacity(), 10);
|
/// assert_eq!(vec.capacity(), 10);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -885,10 +1008,10 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reserves capacity for at least `additional` more elements to be inserted
|
/// Reserves capacity for at least `additional` more elements to be inserted
|
||||||
/// in the given `Vec<T>`. The collection may reserve more space to avoid
|
/// in the given `Vec<T>`. The collection may reserve more space to
|
||||||
/// frequent reallocations. After calling `reserve`, capacity will be
|
/// speculatively avoid frequent reallocations. After calling `reserve`,
|
||||||
/// greater than or equal to `self.len() + additional`. Does nothing if
|
/// capacity will be greater than or equal to `self.len() + additional`.
|
||||||
/// capacity is already sufficient.
|
/// Does nothing if capacity is already sufficient.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
@ -907,10 +1030,12 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
self.buf.reserve(self.len, additional);
|
self.buf.reserve(self.len, additional);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reserves the minimum capacity for exactly `additional` more elements to
|
/// Reserves the minimum capacity for at least `additional` more elements to
|
||||||
/// be inserted in the given `Vec<T>`. After calling `reserve_exact`,
|
/// be inserted in the given `Vec<T>`. Unlike [`reserve`], this will not
|
||||||
/// capacity will be greater than or equal to `self.len() + additional`.
|
/// deliberately over-allocate to speculatively avoid frequent allocations.
|
||||||
/// Does nothing if the capacity is already sufficient.
|
/// After calling `reserve_exact`, capacity will be greater than or equal to
|
||||||
|
/// `self.len() + additional`. Does nothing if the capacity is already
|
||||||
|
/// sufficient.
|
||||||
///
|
///
|
||||||
/// Note that the allocator may give the collection more space than it
|
/// Note that the allocator may give the collection more space than it
|
||||||
/// requests. Therefore, capacity can not be relied upon to be precisely
|
/// requests. Therefore, capacity can not be relied upon to be precisely
|
||||||
@ -936,10 +1061,11 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to reserve capacity for at least `additional` more elements to be inserted
|
/// Tries to reserve capacity for at least `additional` more elements to be inserted
|
||||||
/// in the given `Vec<T>`. The collection may reserve more space to avoid
|
/// in the given `Vec<T>`. The collection may reserve more space to speculatively avoid
|
||||||
/// frequent reallocations. After calling `try_reserve`, capacity will be
|
/// frequent reallocations. After calling `try_reserve`, capacity will be
|
||||||
/// greater than or equal to `self.len() + additional`. Does nothing if
|
/// greater than or equal to `self.len() + additional` if it returns
|
||||||
/// capacity is already sufficient.
|
/// `Ok(())`. Does nothing if capacity is already sufficient. This method
|
||||||
|
/// preserves the contents even if an error occurs.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
@ -971,10 +1097,11 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
self.buf.try_reserve(self.len, additional)
|
self.buf.try_reserve(self.len, additional)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to reserve the minimum capacity for exactly `additional`
|
/// Tries to reserve the minimum capacity for at least `additional`
|
||||||
/// elements to be inserted in the given `Vec<T>`. After calling
|
/// elements to be inserted in the given `Vec<T>`. Unlike [`try_reserve`],
|
||||||
/// `try_reserve_exact`, capacity will be greater than or equal to
|
/// this will not deliberately over-allocate to speculatively avoid frequent
|
||||||
/// `self.len() + additional` if it returns `Ok(())`.
|
/// allocations. After calling `try_reserve_exact`, capacity will be greater
|
||||||
|
/// than or equal to `self.len() + additional` if it returns `Ok(())`.
|
||||||
/// Does nothing if the capacity is already sufficient.
|
/// Does nothing if the capacity is already sufficient.
|
||||||
///
|
///
|
||||||
/// Note that the allocator may give the collection more space than it
|
/// Note that the allocator may give the collection more space than it
|
||||||
@ -1066,7 +1193,8 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
|
|
||||||
/// Converts the vector into [`Box<[T]>`][owned slice].
|
/// Converts the vector into [`Box<[T]>`][owned slice].
|
||||||
///
|
///
|
||||||
/// Note that this will drop any excess capacity.
|
/// If the vector has excess capacity, its items will be moved into a
|
||||||
|
/// newly-allocated buffer with exactly the right capacity.
|
||||||
///
|
///
|
||||||
/// [owned slice]: Box
|
/// [owned slice]: Box
|
||||||
///
|
///
|
||||||
@ -1199,7 +1327,8 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a raw pointer to the vector's buffer.
|
/// Returns a raw pointer to the vector's buffer, or a dangling raw pointer
|
||||||
|
/// valid for zero sized reads if the vector didn't allocate.
|
||||||
///
|
///
|
||||||
/// The caller must ensure that the vector outlives the pointer this
|
/// The caller must ensure that the vector outlives the pointer this
|
||||||
/// function returns, or else it will end up pointing to garbage.
|
/// function returns, or else it will end up pointing to garbage.
|
||||||
@ -1236,7 +1365,8 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
ptr
|
ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an unsafe mutable pointer to the vector's buffer.
|
/// Returns an unsafe mutable pointer to the vector's buffer, or a dangling
|
||||||
|
/// raw pointer valid for zero sized reads if the vector didn't allocate.
|
||||||
///
|
///
|
||||||
/// The caller must ensure that the vector outlives the pointer this
|
/// The caller must ensure that the vector outlives the pointer this
|
||||||
/// function returns, or else it will end up pointing to garbage.
|
/// function returns, or else it will end up pointing to garbage.
|
||||||
@ -1440,9 +1570,6 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let len = self.len();
|
let len = self.len();
|
||||||
if index > len {
|
|
||||||
assert_failed(index, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// space for the new element
|
// space for the new element
|
||||||
if len == self.buf.capacity() {
|
if len == self.buf.capacity() {
|
||||||
@ -1454,9 +1581,15 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
// The spot to put the new value
|
// The spot to put the new value
|
||||||
{
|
{
|
||||||
let p = self.as_mut_ptr().add(index);
|
let p = self.as_mut_ptr().add(index);
|
||||||
// Shift everything over to make space. (Duplicating the
|
if index < len {
|
||||||
// `index`th element into two consecutive places.)
|
// Shift everything over to make space. (Duplicating the
|
||||||
ptr::copy(p, p.offset(1), len - index);
|
// `index`th element into two consecutive places.)
|
||||||
|
ptr::copy(p, p.add(1), len - index);
|
||||||
|
} else if index == len {
|
||||||
|
// No elements need shifting.
|
||||||
|
} else {
|
||||||
|
assert_failed(index, len);
|
||||||
|
}
|
||||||
// Write it in, overwriting the first copy of the `index`th
|
// Write it in, overwriting the first copy of the `index`th
|
||||||
// element.
|
// element.
|
||||||
ptr::write(p, element);
|
ptr::write(p, element);
|
||||||
@ -1513,7 +1646,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
ret = ptr::read(ptr);
|
ret = ptr::read(ptr);
|
||||||
|
|
||||||
// Shift everything down to fill in that spot.
|
// Shift everything down to fill in that spot.
|
||||||
ptr::copy(ptr.offset(1), ptr, len - index - 1);
|
ptr::copy(ptr.add(1), ptr, len - index - 1);
|
||||||
}
|
}
|
||||||
self.set_len(len - 1);
|
self.set_len(len - 1);
|
||||||
ret
|
ret
|
||||||
@ -1562,11 +1695,11 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let mut vec = vec![1, 2, 3, 4];
|
/// let mut vec = vec![1, 2, 3, 4];
|
||||||
/// vec.retain_mut(|x| if *x > 3 {
|
/// vec.retain_mut(|x| if *x <= 3 {
|
||||||
/// false
|
|
||||||
/// } else {
|
|
||||||
/// *x += 1;
|
/// *x += 1;
|
||||||
/// true
|
/// true
|
||||||
|
/// } else {
|
||||||
|
/// false
|
||||||
/// });
|
/// });
|
||||||
/// assert_eq!(vec, [2, 3, 4]);
|
/// assert_eq!(vec, [2, 3, 4]);
|
||||||
/// ```
|
/// ```
|
||||||
@ -1854,6 +1987,51 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Appends an element if there is sufficient spare capacity, otherwise an error is returned
|
||||||
|
/// with the element.
|
||||||
|
///
|
||||||
|
/// Unlike [`push`] this method will not reallocate when there's insufficient capacity.
|
||||||
|
/// The caller should use [`reserve`] or [`try_reserve`] to ensure that there is enough capacity.
|
||||||
|
///
|
||||||
|
/// [`push`]: Vec::push
|
||||||
|
/// [`reserve`]: Vec::reserve
|
||||||
|
/// [`try_reserve`]: Vec::try_reserve
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// A manual, panic-free alternative to [`FromIterator`]:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// #![feature(vec_push_within_capacity)]
|
||||||
|
///
|
||||||
|
/// use std::collections::TryReserveError;
|
||||||
|
/// fn from_iter_fallible<T>(iter: impl Iterator<Item=T>) -> Result<Vec<T>, TryReserveError> {
|
||||||
|
/// let mut vec = Vec::new();
|
||||||
|
/// for value in iter {
|
||||||
|
/// if let Err(value) = vec.push_within_capacity(value) {
|
||||||
|
/// vec.try_reserve(1)?;
|
||||||
|
/// // this cannot fail, the previous line either returned or added at least 1 free slot
|
||||||
|
/// let _ = vec.push_within_capacity(value);
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// Ok(vec)
|
||||||
|
/// }
|
||||||
|
/// assert_eq!(from_iter_fallible(0..100), Ok(Vec::from_iter(0..100)));
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
#[unstable(feature = "vec_push_within_capacity", issue = "100486")]
|
||||||
|
pub fn push_within_capacity(&mut self, value: T) -> Result<(), T> {
|
||||||
|
if self.len == self.buf.capacity() {
|
||||||
|
return Err(value);
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
let end = self.as_mut_ptr().add(self.len);
|
||||||
|
ptr::write(end, value);
|
||||||
|
self.len += 1;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Removes the last element from a vector and returns it, or [`None`] if it
|
/// Removes the last element from a vector and returns it, or [`None`] if it
|
||||||
/// is empty.
|
/// is empty.
|
||||||
///
|
///
|
||||||
@ -1886,7 +2064,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the number of elements in the vector overflows a `usize`.
|
/// Panics if the new capacity exceeds `isize::MAX` bytes.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@ -1980,9 +2158,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
// set self.vec length's to start, to be safe in case Drain is leaked
|
// set self.vec length's to start, to be safe in case Drain is leaked
|
||||||
self.set_len(start);
|
self.set_len(start);
|
||||||
// Use the borrow in the IterMut to indicate borrowing behavior of the
|
let range_slice = slice::from_raw_parts(self.as_ptr().add(start), end - start);
|
||||||
// whole Drain iterator (like &mut T).
|
|
||||||
let range_slice = slice::from_raw_parts_mut(self.as_mut_ptr().add(start), end - start);
|
|
||||||
Drain {
|
Drain {
|
||||||
tail_start: end,
|
tail_start: end,
|
||||||
tail_len: len - end,
|
tail_len: len - end,
|
||||||
@ -2145,7 +2321,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
{
|
{
|
||||||
let len = self.len();
|
let len = self.len();
|
||||||
if new_len > len {
|
if new_len > len {
|
||||||
self.extend_with(new_len - len, ExtendFunc(f));
|
self.extend_trusted(iter::repeat_with(f).take(new_len - len));
|
||||||
} else {
|
} else {
|
||||||
self.truncate(new_len);
|
self.truncate(new_len);
|
||||||
}
|
}
|
||||||
@ -2174,7 +2350,6 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
/// static_ref[0] += 1;
|
/// static_ref[0] += 1;
|
||||||
/// assert_eq!(static_ref, &[2, 2, 3]);
|
/// assert_eq!(static_ref, &[2, 2, 3]);
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(no_global_oom_handling))]
|
|
||||||
#[stable(feature = "vec_leak", since = "1.47.0")]
|
#[stable(feature = "vec_leak", since = "1.47.0")]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn leak<'a>(self) -> &'a mut [T]
|
pub fn leak<'a>(self) -> &'a mut [T]
|
||||||
@ -2469,7 +2644,7 @@ impl<T: Clone, A: Allocator> Vec<T, A> {
|
|||||||
self.reserve(range.len());
|
self.reserve(range.len());
|
||||||
|
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - `slice::range` guarantees that the given range is valid for indexing self
|
// - `slice::range` guarantees that the given range is valid for indexing self
|
||||||
unsafe {
|
unsafe {
|
||||||
self.spec_extend_from_within(range);
|
self.spec_extend_from_within(range);
|
||||||
}
|
}
|
||||||
@ -2501,7 +2676,7 @@ impl<T, A: Allocator, const N: usize> Vec<[T; N], A> {
|
|||||||
#[unstable(feature = "slice_flatten", issue = "95629")]
|
#[unstable(feature = "slice_flatten", issue = "95629")]
|
||||||
pub fn into_flattened(self) -> Vec<T, A> {
|
pub fn into_flattened(self) -> Vec<T, A> {
|
||||||
let (ptr, len, cap, alloc) = self.into_raw_parts_with_alloc();
|
let (ptr, len, cap, alloc) = self.into_raw_parts_with_alloc();
|
||||||
let (new_len, new_cap) = if mem::size_of::<T>() == 0 {
|
let (new_len, new_cap) = if T::IS_ZST {
|
||||||
(len.checked_mul(N).expect("vec len overflow"), usize::MAX)
|
(len.checked_mul(N).expect("vec len overflow"), usize::MAX)
|
||||||
} else {
|
} else {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
@ -2537,16 +2712,6 @@ impl<T: Clone> ExtendWith<T> for ExtendElement<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExtendFunc<F>(F);
|
|
||||||
impl<T, F: FnMut() -> T> ExtendWith<T> for ExtendFunc<F> {
|
|
||||||
fn next(&mut self) -> T {
|
|
||||||
(self.0)()
|
|
||||||
}
|
|
||||||
fn last(mut self) -> T {
|
|
||||||
(self.0)()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, A: Allocator> Vec<T, A> {
|
impl<T, A: Allocator> Vec<T, A> {
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
/// Extend the vector by `n` values, using the given generator.
|
/// Extend the vector by `n` values, using the given generator.
|
||||||
@ -2563,7 +2728,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
// Write all elements except the last one
|
// Write all elements except the last one
|
||||||
for _ in 1..n {
|
for _ in 1..n {
|
||||||
ptr::write(ptr, value.next());
|
ptr::write(ptr, value.next());
|
||||||
ptr = ptr.offset(1);
|
ptr = ptr.add(1);
|
||||||
// Increment the length in every step in case next() panics
|
// Increment the length in every step in case next() panics
|
||||||
local_len.increment_len(1);
|
local_len.increment_len(1);
|
||||||
}
|
}
|
||||||
@ -2592,7 +2757,7 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
// Write all elements except the last one
|
// Write all elements except the last one
|
||||||
for _ in 1..n {
|
for _ in 1..n {
|
||||||
ptr::write(ptr, value.next());
|
ptr::write(ptr, value.next());
|
||||||
ptr = ptr.offset(1);
|
ptr = ptr.add(1);
|
||||||
// Increment the length in every step in case next() panics
|
// Increment the length in every step in case next() panics
|
||||||
local_len.increment_len(1);
|
local_len.increment_len(1);
|
||||||
}
|
}
|
||||||
@ -2664,7 +2829,7 @@ impl<T: Clone, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
|
|||||||
let (this, spare, len) = unsafe { self.split_at_spare_mut_with_len() };
|
let (this, spare, len) = unsafe { self.split_at_spare_mut_with_len() };
|
||||||
|
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - caller guaratees that src is a valid index
|
// - caller guarantees that src is a valid index
|
||||||
let to_clone = unsafe { this.get_unchecked(src) };
|
let to_clone = unsafe { this.get_unchecked(src) };
|
||||||
|
|
||||||
iter::zip(to_clone, spare)
|
iter::zip(to_clone, spare)
|
||||||
@ -2683,13 +2848,13 @@ impl<T: Copy, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
|
|||||||
let (init, spare) = self.split_at_spare_mut();
|
let (init, spare) = self.split_at_spare_mut();
|
||||||
|
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - caller guaratees that `src` is a valid index
|
// - caller guarantees that `src` is a valid index
|
||||||
let source = unsafe { init.get_unchecked(src) };
|
let source = unsafe { init.get_unchecked(src) };
|
||||||
|
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - Both pointers are created from unique slice references (`&mut [_]`)
|
// - Both pointers are created from unique slice references (`&mut [_]`)
|
||||||
// so they are valid and do not overlap.
|
// so they are valid and do not overlap.
|
||||||
// - Elements are :Copy so it's OK to to copy them, without doing
|
// - Elements are :Copy so it's OK to copy them, without doing
|
||||||
// anything with the original values
|
// anything with the original values
|
||||||
// - `count` is equal to the len of `source`, so source is valid for
|
// - `count` is equal to the len of `source`, so source is valid for
|
||||||
// `count` reads
|
// `count` reads
|
||||||
@ -2712,6 +2877,7 @@ impl<T: Copy, A: Allocator> ExtendFromWithinSpec for Vec<T, A> {
|
|||||||
impl<T, A: Allocator> ops::Deref for Vec<T, A> {
|
impl<T, A: Allocator> ops::Deref for Vec<T, A> {
|
||||||
type Target = [T];
|
type Target = [T];
|
||||||
|
|
||||||
|
#[inline]
|
||||||
fn deref(&self) -> &[T] {
|
fn deref(&self) -> &[T] {
|
||||||
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
|
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
|
||||||
}
|
}
|
||||||
@ -2719,6 +2885,7 @@ impl<T, A: Allocator> ops::Deref for Vec<T, A> {
|
|||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
|
impl<T, A: Allocator> ops::DerefMut for Vec<T, A> {
|
||||||
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut [T] {
|
fn deref_mut(&mut self) -> &mut [T] {
|
||||||
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
|
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
|
||||||
}
|
}
|
||||||
@ -2764,7 +2931,7 @@ impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
|
|||||||
|
|
||||||
// HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
|
// HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
|
||||||
// required for this method definition, is not available. Instead use the
|
// required for this method definition, is not available. Instead use the
|
||||||
// `slice::to_vec` function which is only available with cfg(test)
|
// `slice::to_vec` function which is only available with cfg(test)
|
||||||
// NB see the slice::hack module in slice.rs for more information
|
// NB see the slice::hack module in slice.rs for more information
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
@ -2845,19 +3012,22 @@ impl<T, A: Allocator> IntoIterator for Vec<T, A> {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let v = vec!["a".to_string(), "b".to_string()];
|
/// let v = vec!["a".to_string(), "b".to_string()];
|
||||||
/// for s in v.into_iter() {
|
/// let mut v_iter = v.into_iter();
|
||||||
/// // s has type String, not &String
|
///
|
||||||
/// println!("{s}");
|
/// let first_element: Option<String> = v_iter.next();
|
||||||
/// }
|
///
|
||||||
|
/// assert_eq!(first_element, Some("a".to_string()));
|
||||||
|
/// assert_eq!(v_iter.next(), Some("b".to_string()));
|
||||||
|
/// assert_eq!(v_iter.next(), None);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_iter(self) -> IntoIter<T, A> {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut me = ManuallyDrop::new(self);
|
let mut me = ManuallyDrop::new(self);
|
||||||
let alloc = ManuallyDrop::new(ptr::read(me.allocator()));
|
let alloc = ManuallyDrop::new(ptr::read(me.allocator()));
|
||||||
let begin = me.as_mut_ptr();
|
let begin = me.as_mut_ptr();
|
||||||
let end = if mem::size_of::<T>() == 0 {
|
let end = if T::IS_ZST {
|
||||||
arith_offset(begin as *const i8, me.len() as isize) as *const T
|
begin.wrapping_byte_add(me.len())
|
||||||
} else {
|
} else {
|
||||||
begin.add(me.len()) as *const T
|
begin.add(me.len()) as *const T
|
||||||
};
|
};
|
||||||
@ -2879,7 +3049,7 @@ impl<'a, T, A: Allocator> IntoIterator for &'a Vec<T, A> {
|
|||||||
type Item = &'a T;
|
type Item = &'a T;
|
||||||
type IntoIter = slice::Iter<'a, T>;
|
type IntoIter = slice::Iter<'a, T>;
|
||||||
|
|
||||||
fn into_iter(self) -> slice::Iter<'a, T> {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.iter()
|
self.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2889,7 +3059,7 @@ impl<'a, T, A: Allocator> IntoIterator for &'a mut Vec<T, A> {
|
|||||||
type Item = &'a mut T;
|
type Item = &'a mut T;
|
||||||
type IntoIter = slice::IterMut<'a, T>;
|
type IntoIter = slice::IterMut<'a, T>;
|
||||||
|
|
||||||
fn into_iter(self) -> slice::IterMut<'a, T> {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.iter_mut()
|
self.iter_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2969,6 +3139,69 @@ impl<T, A: Allocator> Vec<T, A> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// specific extend for `TrustedLen` iterators, called both by the specializations
|
||||||
|
// and internal places where resolving specialization makes compilation slower
|
||||||
|
#[cfg(not(no_global_oom_handling))]
|
||||||
|
fn extend_trusted(&mut self, iterator: impl iter::TrustedLen<Item = T>) {
|
||||||
|
let (low, high) = iterator.size_hint();
|
||||||
|
if let Some(additional) = high {
|
||||||
|
debug_assert_eq!(
|
||||||
|
low,
|
||||||
|
additional,
|
||||||
|
"TrustedLen iterator's size hint is not exact: {:?}",
|
||||||
|
(low, high)
|
||||||
|
);
|
||||||
|
self.reserve(additional);
|
||||||
|
unsafe {
|
||||||
|
let ptr = self.as_mut_ptr();
|
||||||
|
let mut local_len = SetLenOnDrop::new(&mut self.len);
|
||||||
|
iterator.for_each(move |element| {
|
||||||
|
ptr::write(ptr.add(local_len.current_len()), element);
|
||||||
|
// Since the loop executes user code which can panic we have to update
|
||||||
|
// the length every step to correctly drop what we've written.
|
||||||
|
// NB can't overflow since we would have had to alloc the address space
|
||||||
|
local_len.increment_len(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Per TrustedLen contract a `None` upper bound means that the iterator length
|
||||||
|
// truly exceeds usize::MAX, which would eventually lead to a capacity overflow anyway.
|
||||||
|
// Since the other branch already panics eagerly (via `reserve()`) we do the same here.
|
||||||
|
// This avoids additional codegen for a fallback code path which would eventually
|
||||||
|
// panic anyway.
|
||||||
|
panic!("capacity overflow");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// specific extend for `TrustedLen` iterators, called both by the specializations
|
||||||
|
// and internal places where resolving specialization makes compilation slower
|
||||||
|
fn try_extend_trusted(&mut self, iterator: impl iter::TrustedLen<Item = T>) -> Result<(), TryReserveError> {
|
||||||
|
let (low, high) = iterator.size_hint();
|
||||||
|
if let Some(additional) = high {
|
||||||
|
debug_assert_eq!(
|
||||||
|
low,
|
||||||
|
additional,
|
||||||
|
"TrustedLen iterator's size hint is not exact: {:?}",
|
||||||
|
(low, high)
|
||||||
|
);
|
||||||
|
self.try_reserve(additional)?;
|
||||||
|
unsafe {
|
||||||
|
let ptr = self.as_mut_ptr();
|
||||||
|
let mut local_len = SetLenOnDrop::new(&mut self.len);
|
||||||
|
iterator.for_each(move |element| {
|
||||||
|
ptr::write(ptr.add(local_len.current_len()), element);
|
||||||
|
// Since the loop executes user code which can panic we have to update
|
||||||
|
// the length every step to correctly drop what we've written.
|
||||||
|
// NB can't overflow since we would have had to alloc the address space
|
||||||
|
local_len.increment_len(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(TryReserveErrorKind::CapacityOverflow.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a splicing iterator that replaces the specified range in the vector
|
/// Creates a splicing iterator that replaces the specified range in the vector
|
||||||
/// with the given `replace_with` iterator and yields the removed items.
|
/// with the given `replace_with` iterator and yields the removed items.
|
||||||
/// `replace_with` does not need to be the same length as `range`.
|
/// `replace_with` does not need to be the same length as `range`.
|
||||||
@ -3135,6 +3368,8 @@ unsafe impl<#[may_dangle] T, A: Allocator> Drop for Vec<T, A> {
|
|||||||
#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
|
#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
|
||||||
impl<T> const Default for Vec<T> {
|
impl<T> const Default for Vec<T> {
|
||||||
/// Creates an empty `Vec<T>`.
|
/// Creates an empty `Vec<T>`.
|
||||||
|
///
|
||||||
|
/// The vector will not allocate until elements are pushed onto it.
|
||||||
fn default() -> Vec<T> {
|
fn default() -> Vec<T> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
@ -3227,12 +3462,15 @@ impl<T, const N: usize> From<[T; N]> for Vec<T> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
fn from(s: [T; N]) -> Vec<T> {
|
fn from(s: [T; N]) -> Vec<T> {
|
||||||
<[T]>::into_vec(box s)
|
<[T]>::into_vec(
|
||||||
|
#[rustc_box]
|
||||||
|
Box::new(s),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn from(s: [T; N]) -> Vec<T> {
|
fn from(s: [T; N]) -> Vec<T> {
|
||||||
crate::slice::into_vec(box s)
|
crate::slice::into_vec(Box::new(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3261,7 +3499,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// note: test pulls in libstd, which causes errors here
|
// note: test pulls in std, which causes errors here
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
#[stable(feature = "vec_from_box", since = "1.18.0")]
|
#[stable(feature = "vec_from_box", since = "1.18.0")]
|
||||||
impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
|
impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
|
||||||
@ -3279,7 +3517,7 @@ impl<T, A: Allocator> From<Box<[T], A>> for Vec<T, A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// note: test pulls in libstd, which causes errors here
|
// note: test pulls in std, which causes errors here
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
#[stable(feature = "box_from_vec", since = "1.20.0")]
|
#[stable(feature = "box_from_vec", since = "1.20.0")]
|
||||||
@ -3294,6 +3532,14 @@ impl<T, A: Allocator> From<Vec<T, A>> for Box<[T], A> {
|
|||||||
/// ```
|
/// ```
|
||||||
/// assert_eq!(Box::from(vec![1, 2, 3]), vec![1, 2, 3].into_boxed_slice());
|
/// assert_eq!(Box::from(vec![1, 2, 3]), vec![1, 2, 3].into_boxed_slice());
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// Any excess capacity is removed:
|
||||||
|
/// ```
|
||||||
|
/// let mut vec = Vec::with_capacity(10);
|
||||||
|
/// vec.extend([1, 2, 3]);
|
||||||
|
///
|
||||||
|
/// assert_eq!(Box::from(vec), vec![1, 2, 3].into_boxed_slice());
|
||||||
|
/// ```
|
||||||
fn from(v: Vec<T, A>) -> Self {
|
fn from(v: Vec<T, A>) -> Self {
|
||||||
v.into_boxed_slice()
|
v.into_boxed_slice()
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,11 @@ impl<'a> SetLenOnDrop<'a> {
|
|||||||
pub(super) fn increment_len(&mut self, increment: usize) {
|
pub(super) fn increment_len(&mut self, increment: usize) {
|
||||||
self.local_len += increment;
|
self.local_len += increment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn current_len(&self) -> usize {
|
||||||
|
self.local_len
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for SetLenOnDrop<'_> {
|
impl Drop for SetLenOnDrop<'_> {
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
// SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||||
|
|
||||||
use crate::alloc::Allocator;
|
use crate::alloc::Allocator;
|
||||||
use crate::collections::{TryReserveError, TryReserveErrorKind};
|
use crate::collections::TryReserveError;
|
||||||
use core::iter::TrustedLen;
|
use core::iter::TrustedLen;
|
||||||
use core::ptr::{self};
|
|
||||||
use core::slice::{self};
|
use core::slice::{self};
|
||||||
|
|
||||||
use super::{IntoIter, SetLenOnDrop, Vec};
|
use super::{IntoIter, Vec};
|
||||||
|
|
||||||
// Specialization trait used for Vec::extend
|
// Specialization trait used for Vec::extend
|
||||||
#[cfg(not(no_global_oom_handling))]
|
#[cfg(not(no_global_oom_handling))]
|
||||||
@ -44,36 +43,7 @@ where
|
|||||||
I: TrustedLen<Item = T>,
|
I: TrustedLen<Item = T>,
|
||||||
{
|
{
|
||||||
default fn spec_extend(&mut self, iterator: I) {
|
default fn spec_extend(&mut self, iterator: I) {
|
||||||
// This is the case for a TrustedLen iterator.
|
self.extend_trusted(iterator)
|
||||||
let (low, high) = iterator.size_hint();
|
|
||||||
if let Some(additional) = high {
|
|
||||||
debug_assert_eq!(
|
|
||||||
low,
|
|
||||||
additional,
|
|
||||||
"TrustedLen iterator's size hint is not exact: {:?}",
|
|
||||||
(low, high)
|
|
||||||
);
|
|
||||||
self.reserve(additional);
|
|
||||||
unsafe {
|
|
||||||
let mut ptr = self.as_mut_ptr().add(self.len());
|
|
||||||
let mut local_len = SetLenOnDrop::new(&mut self.len);
|
|
||||||
iterator.for_each(move |element| {
|
|
||||||
ptr::write(ptr, element);
|
|
||||||
ptr = ptr.offset(1);
|
|
||||||
// Since the loop executes user code which can panic we have to bump the pointer
|
|
||||||
// after each step.
|
|
||||||
// NB can't overflow since we would have had to alloc the address space
|
|
||||||
local_len.increment_len(1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Per TrustedLen contract a `None` upper bound means that the iterator length
|
|
||||||
// truly exceeds usize::MAX, which would eventually lead to a capacity overflow anyway.
|
|
||||||
// Since the other branch already panics eagerly (via `reserve()`) we do the same here.
|
|
||||||
// This avoids additional codegen for a fallback code path which would eventually
|
|
||||||
// panic anyway.
|
|
||||||
panic!("capacity overflow");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,32 +52,7 @@ where
|
|||||||
I: TrustedLen<Item = T>,
|
I: TrustedLen<Item = T>,
|
||||||
{
|
{
|
||||||
default fn try_spec_extend(&mut self, iterator: I) -> Result<(), TryReserveError> {
|
default fn try_spec_extend(&mut self, iterator: I) -> Result<(), TryReserveError> {
|
||||||
// This is the case for a TrustedLen iterator.
|
self.try_extend_trusted(iterator)
|
||||||
let (low, high) = iterator.size_hint();
|
|
||||||
if let Some(additional) = high {
|
|
||||||
debug_assert_eq!(
|
|
||||||
low,
|
|
||||||
additional,
|
|
||||||
"TrustedLen iterator's size hint is not exact: {:?}",
|
|
||||||
(low, high)
|
|
||||||
);
|
|
||||||
self.try_reserve(additional)?;
|
|
||||||
unsafe {
|
|
||||||
let mut ptr = self.as_mut_ptr().add(self.len());
|
|
||||||
let mut local_len = SetLenOnDrop::new(&mut self.len);
|
|
||||||
iterator.for_each(move |element| {
|
|
||||||
ptr::write(ptr, element);
|
|
||||||
ptr = ptr.offset(1);
|
|
||||||
// Since the loop executes user code which can panic we have to bump the pointer
|
|
||||||
// after each step.
|
|
||||||
// NB can't overflow since we would have had to alloc the address space
|
|
||||||
local_len.increment_len(1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(TryReserveErrorKind::CapacityOverflow.into())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
//! using this crate.
|
//! using this crate.
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(core_ffi_c)]
|
|
||||||
// See <https://github.com/rust-lang/rust-bindgen/issues/1651>.
|
// See <https://github.com/rust-lang/rust-bindgen/issues/1651>.
|
||||||
#![cfg_attr(test, allow(deref_nullptr))]
|
#![cfg_attr(test, allow(deref_nullptr))]
|
||||||
#![cfg_attr(test, allow(unaligned_references))]
|
#![cfg_attr(test, allow(unaligned_references))]
|
||||||
|
@ -67,6 +67,8 @@ macro_rules! build_error {
|
|||||||
/// assert!(n > 1); // Run-time check
|
/// assert!(n > 1); // Run-time check
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`static_assert!`]: crate::static_assert!
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! build_assert {
|
macro_rules! build_assert {
|
||||||
($cond:expr $(,)?) => {{
|
($cond:expr $(,)?) => {{
|
||||||
|
@ -197,6 +197,7 @@
|
|||||||
//! [`Opaque`]: kernel::types::Opaque
|
//! [`Opaque`]: kernel::types::Opaque
|
||||||
//! [`Opaque::ffi_init`]: kernel::types::Opaque::ffi_init
|
//! [`Opaque::ffi_init`]: kernel::types::Opaque::ffi_init
|
||||||
//! [`pin_data`]: ::macros::pin_data
|
//! [`pin_data`]: ::macros::pin_data
|
||||||
|
//! [`pin_init!`]: crate::pin_init!
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{self, Error},
|
error::{self, Error},
|
||||||
@ -255,6 +256,8 @@ pub mod macros;
|
|||||||
/// A normal `let` binding with optional type annotation. The expression is expected to implement
|
/// A normal `let` binding with optional type annotation. The expression is expected to implement
|
||||||
/// [`PinInit`]/[`Init`] with the error type [`Infallible`]. If you want to use a different error
|
/// [`PinInit`]/[`Init`] with the error type [`Infallible`]. If you want to use a different error
|
||||||
/// type, then use [`stack_try_pin_init!`].
|
/// type, then use [`stack_try_pin_init!`].
|
||||||
|
///
|
||||||
|
/// [`stack_try_pin_init!`]: crate::stack_try_pin_init!
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! stack_pin_init {
|
macro_rules! stack_pin_init {
|
||||||
(let $var:ident $(: $t:ty)? = $val:expr) => {
|
(let $var:ident $(: $t:ty)? = $val:expr) => {
|
||||||
@ -804,6 +807,8 @@ macro_rules! try_pin_init {
|
|||||||
///
|
///
|
||||||
/// This initializer is for initializing data in-place that might later be moved. If you want to
|
/// This initializer is for initializing data in-place that might later be moved. If you want to
|
||||||
/// pin-initialize, use [`pin_init!`].
|
/// pin-initialize, use [`pin_init!`].
|
||||||
|
///
|
||||||
|
/// [`try_init!`]: crate::try_init!
|
||||||
// For a detailed example of how this macro works, see the module documentation of the hidden
|
// For a detailed example of how this macro works, see the module documentation of the hidden
|
||||||
// module `__internal` inside of `init/__internal.rs`.
|
// module `__internal` inside of `init/__internal.rs`.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -14,12 +14,8 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(allocator_api)]
|
#![feature(allocator_api)]
|
||||||
#![feature(coerce_unsized)]
|
#![feature(coerce_unsized)]
|
||||||
#![feature(core_ffi_c)]
|
|
||||||
#![feature(dispatch_from_dyn)]
|
#![feature(dispatch_from_dyn)]
|
||||||
#![feature(explicit_generic_args_with_impl_trait)]
|
|
||||||
#![feature(generic_associated_types)]
|
|
||||||
#![feature(new_uninit)]
|
#![feature(new_uninit)]
|
||||||
#![feature(pin_macro)]
|
|
||||||
#![feature(receiver_trait)]
|
#![feature(receiver_trait)]
|
||||||
#![feature(unsize)]
|
#![feature(unsize)]
|
||||||
|
|
||||||
|
@ -137,6 +137,8 @@
|
|||||||
/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
|
/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
|
||||||
/// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html
|
/// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html
|
||||||
/// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html
|
/// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html
|
||||||
|
/// [`pr_info`]: crate::pr_info!
|
||||||
|
/// [`pr_debug`]: crate::pr_debug!
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! dbg {
|
macro_rules! dbg {
|
||||||
// NOTE: We cannot use `concat!` to make a static string as a format argument
|
// NOTE: We cannot use `concat!` to make a static string as a format argument
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
//! userspace APIs.
|
//! userspace APIs.
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(core_ffi_c)]
|
|
||||||
// See <https://github.com/rust-lang/rust-bindgen/issues/1651>.
|
// See <https://github.com/rust-lang/rust-bindgen/issues/1651>.
|
||||||
#![cfg_attr(test, allow(deref_nullptr))]
|
#![cfg_attr(test, allow(deref_nullptr))]
|
||||||
#![cfg_attr(test, allow(unaligned_references))]
|
#![cfg_attr(test, allow(unaligned_references))]
|
||||||
|
@ -277,7 +277,7 @@ $(obj)/%.lst: $(src)/%.c FORCE
|
|||||||
# Compile Rust sources (.rs)
|
# Compile Rust sources (.rs)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
rust_allowed_features := core_ffi_c,explicit_generic_args_with_impl_trait,new_uninit,pin_macro
|
rust_allowed_features := new_uninit
|
||||||
|
|
||||||
rust_common_cmd = \
|
rust_common_cmd = \
|
||||||
RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \
|
RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \
|
||||||
|
@ -27,7 +27,7 @@ llvm)
|
|||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
rustc)
|
rustc)
|
||||||
echo 1.62.0
|
echo 1.68.2
|
||||||
;;
|
;;
|
||||||
bindgen)
|
bindgen)
|
||||||
echo 0.56.0
|
echo 0.56.0
|
||||||
|
Loading…
Reference in New Issue
Block a user