Loading...
Note: File does not exist in v3.5.6.
1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3use crate::boxed::Box;
4
5#[rustc_specialization_trait]
6pub(super) unsafe trait IsZero {
7 /// Whether this value's representation is all zeros
8 fn is_zero(&self) -> bool;
9}
10
11macro_rules! impl_is_zero {
12 ($t:ty, $is_zero:expr) => {
13 unsafe impl IsZero for $t {
14 #[inline]
15 fn is_zero(&self) -> bool {
16 $is_zero(*self)
17 }
18 }
19 };
20}
21
22impl_is_zero!(i16, |x| x == 0);
23impl_is_zero!(i32, |x| x == 0);
24impl_is_zero!(i64, |x| x == 0);
25impl_is_zero!(i128, |x| x == 0);
26impl_is_zero!(isize, |x| x == 0);
27
28impl_is_zero!(u16, |x| x == 0);
29impl_is_zero!(u32, |x| x == 0);
30impl_is_zero!(u64, |x| x == 0);
31impl_is_zero!(u128, |x| x == 0);
32impl_is_zero!(usize, |x| x == 0);
33
34impl_is_zero!(bool, |x| x == false);
35impl_is_zero!(char, |x| x == '\0');
36
37impl_is_zero!(f32, |x: f32| x.to_bits() == 0);
38impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
39
40unsafe impl<T> IsZero for *const T {
41 #[inline]
42 fn is_zero(&self) -> bool {
43 (*self).is_null()
44 }
45}
46
47unsafe impl<T> IsZero for *mut T {
48 #[inline]
49 fn is_zero(&self) -> bool {
50 (*self).is_null()
51 }
52}
53
54unsafe impl<T: IsZero, const N: usize> IsZero for [T; N] {
55 #[inline]
56 fn is_zero(&self) -> bool {
57 // Because this is generated as a runtime check, it's not obvious that
58 // it's worth doing if the array is really long. The threshold here
59 // is largely arbitrary, but was picked because as of 2022-05-01 LLVM
60 // can const-fold the check in `vec![[0; 32]; n]` but not in
61 // `vec![[0; 64]; n]`: https://godbolt.org/z/WTzjzfs5b
62 // Feel free to tweak if you have better evidence.
63
64 N <= 32 && self.iter().all(IsZero::is_zero)
65 }
66}
67
68// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
69// For fat pointers, the bytes that would be the pointer metadata in the `Some`
70// variant are padding in the `None` variant, so ignoring them and
71// zero-initializing instead is ok.
72// `Option<&mut T>` never implements `Clone`, so there's no need for an impl of
73// `SpecFromElem`.
74
75unsafe impl<T: ?Sized> IsZero for Option<&T> {
76 #[inline]
77 fn is_zero(&self) -> bool {
78 self.is_none()
79 }
80}
81
82unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
83 #[inline]
84 fn is_zero(&self) -> bool {
85 self.is_none()
86 }
87}
88
89// `Option<num::NonZeroU32>` and similar have a representation guarantee that
90// they're the same size as the corresponding `u32` type, as well as a guarantee
91// that transmuting between `NonZeroU32` and `Option<num::NonZeroU32>` works.
92// While the documentation officially makes it UB to transmute from `None`,
93// we're the standard library so we can make extra inferences, and we know that
94// the only niche available to represent `None` is the one that's all zeros.
95
96macro_rules! impl_is_zero_option_of_nonzero {
97 ($($t:ident,)+) => {$(
98 unsafe impl IsZero for Option<core::num::$t> {
99 #[inline]
100 fn is_zero(&self) -> bool {
101 self.is_none()
102 }
103 }
104 )+};
105}
106
107impl_is_zero_option_of_nonzero!(
108 NonZeroU8,
109 NonZeroU16,
110 NonZeroU32,
111 NonZeroU64,
112 NonZeroU128,
113 NonZeroI8,
114 NonZeroI16,
115 NonZeroI32,
116 NonZeroI64,
117 NonZeroI128,
118 NonZeroUsize,
119 NonZeroIsize,
120);