162306a36Sopenharmony_ci// SPDX-License-Identifier: Apache-2.0 OR MIT 262306a36Sopenharmony_ci 362306a36Sopenharmony_ciuse core::num::{Saturating, Wrapping}; 462306a36Sopenharmony_ci 562306a36Sopenharmony_ciuse crate::boxed::Box; 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#[rustc_specialization_trait] 862306a36Sopenharmony_cipub(super) unsafe trait IsZero { 962306a36Sopenharmony_ci /// Whether this value's representation is all zeros, 1062306a36Sopenharmony_ci /// or can be represented with all zeroes. 1162306a36Sopenharmony_ci fn is_zero(&self) -> bool; 1262306a36Sopenharmony_ci} 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cimacro_rules! impl_is_zero { 1562306a36Sopenharmony_ci ($t:ty, $is_zero:expr) => { 1662306a36Sopenharmony_ci unsafe impl IsZero for $t { 1762306a36Sopenharmony_ci #[inline] 1862306a36Sopenharmony_ci fn is_zero(&self) -> bool { 1962306a36Sopenharmony_ci $is_zero(*self) 2062306a36Sopenharmony_ci } 2162306a36Sopenharmony_ci } 2262306a36Sopenharmony_ci }; 2362306a36Sopenharmony_ci} 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ciimpl_is_zero!(i8, |x| x == 0); // It is needed to impl for arrays and tuples of i8. 2662306a36Sopenharmony_ciimpl_is_zero!(i16, |x| x == 0); 2762306a36Sopenharmony_ciimpl_is_zero!(i32, |x| x == 0); 2862306a36Sopenharmony_ciimpl_is_zero!(i64, |x| x == 0); 2962306a36Sopenharmony_ciimpl_is_zero!(i128, |x| x == 0); 3062306a36Sopenharmony_ciimpl_is_zero!(isize, |x| x == 0); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ciimpl_is_zero!(u8, |x| x == 0); // It is needed to impl for arrays and tuples of u8. 3362306a36Sopenharmony_ciimpl_is_zero!(u16, |x| x == 0); 3462306a36Sopenharmony_ciimpl_is_zero!(u32, |x| x == 0); 3562306a36Sopenharmony_ciimpl_is_zero!(u64, |x| x == 0); 3662306a36Sopenharmony_ciimpl_is_zero!(u128, |x| x == 0); 3762306a36Sopenharmony_ciimpl_is_zero!(usize, |x| x == 0); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciimpl_is_zero!(bool, |x| x == false); 4062306a36Sopenharmony_ciimpl_is_zero!(char, |x| x == '\0'); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ciimpl_is_zero!(f32, |x: f32| x.to_bits() == 0); 4362306a36Sopenharmony_ciimpl_is_zero!(f64, |x: f64| x.to_bits() == 0); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ciunsafe impl<T> IsZero for *const T { 4662306a36Sopenharmony_ci #[inline] 4762306a36Sopenharmony_ci fn is_zero(&self) -> bool { 4862306a36Sopenharmony_ci (*self).is_null() 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ciunsafe impl<T> IsZero for *mut T { 5362306a36Sopenharmony_ci #[inline] 5462306a36Sopenharmony_ci fn is_zero(&self) -> bool { 5562306a36Sopenharmony_ci (*self).is_null() 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciunsafe impl<T: IsZero, const N: usize> IsZero for [T; N] { 6062306a36Sopenharmony_ci #[inline] 6162306a36Sopenharmony_ci fn is_zero(&self) -> bool { 6262306a36Sopenharmony_ci // Because this is generated as a runtime check, it's not obvious that 6362306a36Sopenharmony_ci // it's worth doing if the array is really long. The threshold here 6462306a36Sopenharmony_ci // is largely arbitrary, but was picked because as of 2022-07-01 LLVM 6562306a36Sopenharmony_ci // fails to const-fold the check in `vec![[1; 32]; n]` 6662306a36Sopenharmony_ci // See https://github.com/rust-lang/rust/pull/97581#issuecomment-1166628022 6762306a36Sopenharmony_ci // Feel free to tweak if you have better evidence. 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci N <= 16 && self.iter().all(IsZero::is_zero) 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci// This is recursive macro. 7462306a36Sopenharmony_cimacro_rules! impl_for_tuples { 7562306a36Sopenharmony_ci // Stopper 7662306a36Sopenharmony_ci () => { 7762306a36Sopenharmony_ci // No use for implementing for empty tuple because it is ZST. 7862306a36Sopenharmony_ci }; 7962306a36Sopenharmony_ci ($first_arg:ident $(,$rest:ident)*) => { 8062306a36Sopenharmony_ci unsafe impl <$first_arg: IsZero, $($rest: IsZero,)*> IsZero for ($first_arg, $($rest,)*){ 8162306a36Sopenharmony_ci #[inline] 8262306a36Sopenharmony_ci fn is_zero(&self) -> bool{ 8362306a36Sopenharmony_ci // Destructure tuple to N references 8462306a36Sopenharmony_ci // Rust allows to hide generic params by local variable names. 8562306a36Sopenharmony_ci #[allow(non_snake_case)] 8662306a36Sopenharmony_ci let ($first_arg, $($rest,)*) = self; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci $first_arg.is_zero() 8962306a36Sopenharmony_ci $( && $rest.is_zero() )* 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci impl_for_tuples!($($rest),*); 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciimpl_for_tuples!(A, B, C, D, E, F, G, H); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null. 10062306a36Sopenharmony_ci// For fat pointers, the bytes that would be the pointer metadata in the `Some` 10162306a36Sopenharmony_ci// variant are padding in the `None` variant, so ignoring them and 10262306a36Sopenharmony_ci// zero-initializing instead is ok. 10362306a36Sopenharmony_ci// `Option<&mut T>` never implements `Clone`, so there's no need for an impl of 10462306a36Sopenharmony_ci// `SpecFromElem`. 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ciunsafe impl<T: ?Sized> IsZero for Option<&T> { 10762306a36Sopenharmony_ci #[inline] 10862306a36Sopenharmony_ci fn is_zero(&self) -> bool { 10962306a36Sopenharmony_ci self.is_none() 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ciunsafe impl<T: ?Sized> IsZero for Option<Box<T>> { 11462306a36Sopenharmony_ci #[inline] 11562306a36Sopenharmony_ci fn is_zero(&self) -> bool { 11662306a36Sopenharmony_ci self.is_none() 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci// `Option<num::NonZeroU32>` and similar have a representation guarantee that 12162306a36Sopenharmony_ci// they're the same size as the corresponding `u32` type, as well as a guarantee 12262306a36Sopenharmony_ci// that transmuting between `NonZeroU32` and `Option<num::NonZeroU32>` works. 12362306a36Sopenharmony_ci// While the documentation officially makes it UB to transmute from `None`, 12462306a36Sopenharmony_ci// we're the standard library so we can make extra inferences, and we know that 12562306a36Sopenharmony_ci// the only niche available to represent `None` is the one that's all zeros. 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cimacro_rules! impl_is_zero_option_of_nonzero { 12862306a36Sopenharmony_ci ($($t:ident,)+) => {$( 12962306a36Sopenharmony_ci unsafe impl IsZero for Option<core::num::$t> { 13062306a36Sopenharmony_ci #[inline] 13162306a36Sopenharmony_ci fn is_zero(&self) -> bool { 13262306a36Sopenharmony_ci self.is_none() 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci )+}; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ciimpl_is_zero_option_of_nonzero!( 13962306a36Sopenharmony_ci NonZeroU8, 14062306a36Sopenharmony_ci NonZeroU16, 14162306a36Sopenharmony_ci NonZeroU32, 14262306a36Sopenharmony_ci NonZeroU64, 14362306a36Sopenharmony_ci NonZeroU128, 14462306a36Sopenharmony_ci NonZeroI8, 14562306a36Sopenharmony_ci NonZeroI16, 14662306a36Sopenharmony_ci NonZeroI32, 14762306a36Sopenharmony_ci NonZeroI64, 14862306a36Sopenharmony_ci NonZeroI128, 14962306a36Sopenharmony_ci NonZeroUsize, 15062306a36Sopenharmony_ci NonZeroIsize, 15162306a36Sopenharmony_ci); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cimacro_rules! impl_is_zero_option_of_num { 15462306a36Sopenharmony_ci ($($t:ty,)+) => {$( 15562306a36Sopenharmony_ci unsafe impl IsZero for Option<$t> { 15662306a36Sopenharmony_ci #[inline] 15762306a36Sopenharmony_ci fn is_zero(&self) -> bool { 15862306a36Sopenharmony_ci const { 15962306a36Sopenharmony_ci let none: Self = unsafe { core::mem::MaybeUninit::zeroed().assume_init() }; 16062306a36Sopenharmony_ci assert!(none.is_none()); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci self.is_none() 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci )+}; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ciimpl_is_zero_option_of_num!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize,); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ciunsafe impl<T: IsZero> IsZero for Wrapping<T> { 17162306a36Sopenharmony_ci #[inline] 17262306a36Sopenharmony_ci fn is_zero(&self) -> bool { 17362306a36Sopenharmony_ci self.0.is_zero() 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ciunsafe impl<T: IsZero> IsZero for Saturating<T> { 17862306a36Sopenharmony_ci #[inline] 17962306a36Sopenharmony_ci fn is_zero(&self) -> bool { 18062306a36Sopenharmony_ci self.0.is_zero() 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cimacro_rules! impl_for_optional_bool { 18562306a36Sopenharmony_ci ($($t:ty,)+) => {$( 18662306a36Sopenharmony_ci unsafe impl IsZero for $t { 18762306a36Sopenharmony_ci #[inline] 18862306a36Sopenharmony_ci fn is_zero(&self) -> bool { 18962306a36Sopenharmony_ci // SAFETY: This is *not* a stable layout guarantee, but 19062306a36Sopenharmony_ci // inside `core` we're allowed to rely on the current rustc 19162306a36Sopenharmony_ci // behaviour that options of bools will be one byte with 19262306a36Sopenharmony_ci // no padding, so long as they're nested less than 254 deep. 19362306a36Sopenharmony_ci let raw: u8 = unsafe { core::mem::transmute(*self) }; 19462306a36Sopenharmony_ci raw == 0 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci )+}; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ciimpl_for_optional_bool! { 20062306a36Sopenharmony_ci Option<bool>, 20162306a36Sopenharmony_ci Option<Option<bool>>, 20262306a36Sopenharmony_ci Option<Option<Option<bool>>>, 20362306a36Sopenharmony_ci // Could go further, but not worth the metadata overhead 20462306a36Sopenharmony_ci} 205