1+ use core:: mem:: SizedTypeProperties ;
12use core:: num:: { NonZero , Saturating , Wrapping } ;
23
34use crate :: boxed:: Box ;
@@ -20,6 +21,8 @@ macro_rules! impl_is_zero {
2021 } ;
2122}
2223
24+ impl_is_zero ! ( ( ) , |_: ( ) | true ) ; // It is needed to impl for arrays and tuples of ().
25+
2326impl_is_zero ! ( i8 , |x| x == 0 ) ; // It is needed to impl for arrays and tuples of i8.
2427impl_is_zero ! ( i16 , |x| x == 0 ) ;
2528impl_is_zero ! ( i32 , |x| x == 0 ) ;
@@ -43,25 +46,45 @@ impl_is_zero!(f64, |x: f64| x.to_bits() == 0);
4346// `IsZero` cannot be soundly implemented for pointers because of provenance
4447// (see #135338).
4548
49+ unsafe impl < T , const N : usize > IsZero for [ T ; N ] {
50+ #[ inline]
51+ default fn is_zero ( & self ) -> bool {
52+ // If the array is of length zero,
53+ // then it doesn't actually contain any `T`s,
54+ // so `T::clone` doesn't need to be called,
55+ // and we can "zero-initialize" all zero bytes of the array.
56+ N == 0
57+ }
58+ }
59+
4660unsafe impl < T : IsZero , const N : usize > IsZero for [ T ; N ] {
4761 #[ inline]
4862 fn is_zero ( & self ) -> bool {
49- // Because this is generated as a runtime check, it's not obvious that
50- // it's worth doing if the array is really long. The threshold here
51- // is largely arbitrary, but was picked because as of 2022-07-01 LLVM
52- // fails to const-fold the check in `vec![[1; 32]; n]`
53- // See https://github.com/rust-lang/rust/pull/97581#issuecomment-1166628022
54- // Feel free to tweak if you have better evidence.
55-
56- N <= 16 && self . iter ( ) . all ( IsZero :: is_zero)
63+ if T :: IS_ZST {
64+ // If T is a ZST, then there is at most one possible value of `T`,
65+ // so we only need to check one element for zeroness.
66+ // We could probably just return `true` here, since implementing
67+ // `IsZero` for a zero-sized type such that `self.is_zero()` returns
68+ // `false` would be useless, but to be safe we check anyway.
69+ self . get ( 0 ) . is_none_or ( IsZero :: is_zero)
70+ } else {
71+ // Because this is generated as a runtime check, it's not obvious that
72+ // it's worth doing if the array is really long. The threshold here
73+ // is largely arbitrary, but was picked because as of 2022-07-01 LLVM
74+ // fails to const-fold the check in `vec![[1; 32]; n]`
75+ // See https://github.com/rust-lang/rust/pull/97581#issuecomment-1166628022
76+ // Feel free to tweak if you have better evidence.
77+
78+ N <= 16 && self . iter ( ) . all ( IsZero :: is_zero)
79+ }
5780 }
5881}
5982
6083// This is recursive macro.
6184macro_rules! impl_is_zero_tuples {
6285 // Stopper
6386 ( ) => {
64- // No use for implementing for empty tuple because it is ZST .
87+ // We already have an impl for () above .
6588 } ;
6689 ( $first_arg: ident $( , $rest: ident) * ) => {
6790 unsafe impl <$first_arg: IsZero , $( $rest: IsZero , ) * > IsZero for ( $first_arg, $( $rest, ) * ) {
0 commit comments