mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
This is a subset of the Rust standard library `alloc` crate, version 1.62.0, licensed under "Apache-2.0 OR MIT", from: https://github.com/rust-lang/rust/tree/1.62.0/library/alloc/src The files are copied as-is, with no modifications whatsoever (not even adding the SPDX identifiers). For copyright details, please see: https://github.com/rust-lang/rust/blob/1.62.0/COPYRIGHT The next patch modifies these files as needed for use within the kernel. This patch split allows reviewers to double-check the import and to clearly see the differences introduced. Vendoring `alloc`, at least for the moment, allows us to have fallible allocations support (i.e. the `try_*` versions of methods which return a `Result` instead of panicking) early on. It also gives a bit more freedom to experiment with new interfaces and to iterate quickly. Eventually, the goal is to have everything the kernel needs in upstream `alloc` and drop it from the kernel tree. For a summary of work on `alloc` happening upstream, please see: https://github.com/Rust-for-Linux/linux/issues/408 The following script may be used to verify the contents: for path in $(cd rust/alloc/ && find . -type f -name '*.rs'); do curl --silent --show-error --location \ https://github.com/rust-lang/rust/raw/1.62.0/library/alloc/src/$path \ | diff --unified rust/alloc/$path - && echo $path: OK done Reviewed-by: Kees Cook <keescook@chromium.org> Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com> Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com> Co-developed-by: Wedson Almeida Filho <wedsonaf@google.com> Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
118 lines
3.2 KiB
Rust
118 lines
3.2 KiB
Rust
use crate::boxed::Box;
|
|
|
|
#[rustc_specialization_trait]
|
|
pub(super) unsafe trait IsZero {
|
|
/// Whether this value's representation is all zeros
|
|
fn is_zero(&self) -> bool;
|
|
}
|
|
|
|
macro_rules! impl_is_zero {
|
|
($t:ty, $is_zero:expr) => {
|
|
unsafe impl IsZero for $t {
|
|
#[inline]
|
|
fn is_zero(&self) -> bool {
|
|
$is_zero(*self)
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
impl_is_zero!(i16, |x| x == 0);
|
|
impl_is_zero!(i32, |x| x == 0);
|
|
impl_is_zero!(i64, |x| x == 0);
|
|
impl_is_zero!(i128, |x| x == 0);
|
|
impl_is_zero!(isize, |x| x == 0);
|
|
|
|
impl_is_zero!(u16, |x| x == 0);
|
|
impl_is_zero!(u32, |x| x == 0);
|
|
impl_is_zero!(u64, |x| x == 0);
|
|
impl_is_zero!(u128, |x| x == 0);
|
|
impl_is_zero!(usize, |x| x == 0);
|
|
|
|
impl_is_zero!(bool, |x| x == false);
|
|
impl_is_zero!(char, |x| x == '\0');
|
|
|
|
impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
|
|
impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
|
|
|
|
unsafe impl<T> IsZero for *const T {
|
|
#[inline]
|
|
fn is_zero(&self) -> bool {
|
|
(*self).is_null()
|
|
}
|
|
}
|
|
|
|
unsafe impl<T> IsZero for *mut T {
|
|
#[inline]
|
|
fn is_zero(&self) -> bool {
|
|
(*self).is_null()
|
|
}
|
|
}
|
|
|
|
unsafe impl<T: IsZero, const N: usize> IsZero for [T; N] {
|
|
#[inline]
|
|
fn is_zero(&self) -> bool {
|
|
// 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
|
|
// is largely arbitrary, but was picked because as of 2022-05-01 LLVM
|
|
// can const-fold the check in `vec![[0; 32]; n]` but not in
|
|
// `vec![[0; 64]; n]`: https://godbolt.org/z/WTzjzfs5b
|
|
// Feel free to tweak if you have better evidence.
|
|
|
|
N <= 32 && self.iter().all(IsZero::is_zero)
|
|
}
|
|
}
|
|
|
|
// `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`
|
|
// variant are padding in the `None` variant, so ignoring them and
|
|
// zero-initializing instead is ok.
|
|
// `Option<&mut T>` never implements `Clone`, so there's no need for an impl of
|
|
// `SpecFromElem`.
|
|
|
|
unsafe impl<T: ?Sized> IsZero for Option<&T> {
|
|
#[inline]
|
|
fn is_zero(&self) -> bool {
|
|
self.is_none()
|
|
}
|
|
}
|
|
|
|
unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
|
|
#[inline]
|
|
fn is_zero(&self) -> bool {
|
|
self.is_none()
|
|
}
|
|
}
|
|
|
|
// `Option<num::NonZeroU32>` and similar have a representation guarantee that
|
|
// they're the same size as the corresponding `u32` type, as well as a guarantee
|
|
// that transmuting between `NonZeroU32` and `Option<num::NonZeroU32>` works.
|
|
// While the documentation officially makes it UB to transmute from `None`,
|
|
// we're the standard library so we can make extra inferences, and we know that
|
|
// the only niche available to represent `None` is the one that's all zeros.
|
|
|
|
macro_rules! impl_is_zero_option_of_nonzero {
|
|
($($t:ident,)+) => {$(
|
|
unsafe impl IsZero for Option<core::num::$t> {
|
|
#[inline]
|
|
fn is_zero(&self) -> bool {
|
|
self.is_none()
|
|
}
|
|
}
|
|
)+};
|
|
}
|
|
|
|
impl_is_zero_option_of_nonzero!(
|
|
NonZeroU8,
|
|
NonZeroU16,
|
|
NonZeroU32,
|
|
NonZeroU64,
|
|
NonZeroU128,
|
|
NonZeroI8,
|
|
NonZeroI16,
|
|
NonZeroI32,
|
|
NonZeroI64,
|
|
NonZeroI128,
|
|
NonZeroUsize,
|
|
NonZeroIsize,
|
|
);
|