Skip to content

Commit 9aa4830

Browse files
committedJan 20, 2024
Manually implement derived NonZero traits.
1 parent 227abac commit 9aa4830

File tree

3 files changed

+176
-8
lines changed

3 files changed

+176
-8
lines changed
 

‎library/core/src/num/nonzero.rs

+174-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
//! Definitions of integer that is known not to equal zero.
22
3+
use crate::cmp::Ordering;
34
use crate::fmt;
5+
use crate::hash::{Hash, Hasher};
6+
use crate::marker::StructuralPartialEq;
47
use crate::ops::{BitOr, BitOrAssign, Div, Neg, Rem};
58
use crate::str::FromStr;
69

@@ -31,13 +34,6 @@ pub trait ZeroablePrimitive: Sized + Copy + private::Sealed {
3134
type NonZero;
3235
}
3336

34-
#[unstable(
35-
feature = "nonzero_internals",
36-
reason = "implementation detail which may disappear or be replaced at any time",
37-
issue = "none"
38-
)]
39-
pub(crate) type NonZero<T> = <T as ZeroablePrimitive>::NonZero;
40-
4137
macro_rules! impl_zeroable_primitive {
4238
($NonZero:ident ( $primitive:ty )) => {
4339
#[unstable(
@@ -71,6 +67,174 @@ impl_zeroable_primitive!(NonZeroI64(i64));
7167
impl_zeroable_primitive!(NonZeroI128(i128));
7268
impl_zeroable_primitive!(NonZeroIsize(isize));
7369

70+
/// A value that is known not to equal zero.
71+
///
72+
/// This enables some memory layout optimization.
73+
/// For example, `Option<NonZero<u32>>` is the same size as `u32`:
74+
///
75+
/// ```rust
76+
/// #![feature(generic_nonzero)]
77+
///
78+
/// use core::mem::size_of;
79+
/// assert_eq!(size_of::<Option<core::num::NonZero<u32>>>(), size_of::<u32>());
80+
/// ```
81+
#[unstable(feature = "generic_nonzero", issue = "82363")]
82+
#[derive(Clone, Copy)]
83+
#[repr(transparent)]
84+
#[rustc_layout_scalar_valid_range_start(1)]
85+
#[rustc_nonnull_optimization_guaranteed]
86+
#[rustc_diagnostic_item = "NonZero"]
87+
pub struct NonZero2<T: ZeroablePrimitive>(T);
88+
89+
#[unstable(
90+
feature = "nonzero_internals",
91+
reason = "implementation detail which may disappear or be replaced at any time",
92+
issue = "none"
93+
)]
94+
pub(crate) type NonZero<T> = <T as ZeroablePrimitive>::NonZero;
95+
96+
macro_rules! impl_nonzero_traits {
97+
(#[$stability:meta] $Ty:ty) => {
98+
#[$stability]
99+
impl Clone for $Ty {
100+
#[inline]
101+
fn clone(&self) -> Self {
102+
#[allow(unused_unsafe)]
103+
// SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values.
104+
unsafe {
105+
Self(self.0)
106+
}
107+
}
108+
}
109+
110+
#[$stability]
111+
impl PartialEq for $Ty {
112+
#[inline]
113+
fn eq(&self, other: &Self) -> bool {
114+
#[allow(unused_unsafe)]
115+
// SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values.
116+
unsafe {
117+
self.0 == other.0
118+
}
119+
}
120+
121+
#[inline]
122+
fn ne(&self, other: &Self) -> bool {
123+
#[allow(unused_unsafe)]
124+
// SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values.
125+
unsafe {
126+
self.0 != other.0
127+
}
128+
}
129+
}
130+
131+
#[$stability]
132+
#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
133+
impl StructuralPartialEq for $Ty {}
134+
135+
#[$stability]
136+
impl PartialOrd for $Ty {
137+
#[inline]
138+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
139+
#[allow(unused_unsafe)]
140+
// SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values.
141+
unsafe {
142+
self.0.partial_cmp(&other.0)
143+
}
144+
}
145+
146+
#[inline]
147+
fn lt(&self, other: &Self) -> bool {
148+
#[allow(unused_unsafe)]
149+
// SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values.
150+
unsafe {
151+
self.0 < other.0
152+
}
153+
}
154+
155+
#[inline]
156+
fn le(&self, other: &Self) -> bool {
157+
#[allow(unused_unsafe)]
158+
// SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values.
159+
unsafe {
160+
self.0 <= other.0
161+
}
162+
}
163+
164+
#[inline]
165+
fn gt(&self, other: &Self) -> bool {
166+
#[allow(unused_unsafe)]
167+
// SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values.
168+
unsafe {
169+
self.0 > other.0
170+
}
171+
}
172+
173+
#[inline]
174+
fn ge(&self, other: &Self) -> bool {
175+
#[allow(unused_unsafe)]
176+
// SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values.
177+
unsafe {
178+
self.0 >= other.0
179+
}
180+
}
181+
}
182+
183+
#[$stability]
184+
impl Ord for $Ty {
185+
fn cmp(&self, other: &Self) -> Ordering {
186+
#[allow(unused_unsafe)]
187+
// SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values.
188+
unsafe {
189+
self.0.cmp(&other.0)
190+
}
191+
}
192+
193+
fn max(self, other: Self) -> Self {
194+
#[allow(unused_unsafe)]
195+
// SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values,
196+
// and the maximum of two non-zero values is still non-zero.
197+
unsafe {
198+
Self(self.0.max(other.0))
199+
}
200+
}
201+
202+
fn min(self, other: Self) -> Self {
203+
#[allow(unused_unsafe)]
204+
// SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values,
205+
// and the minimum of two non-zero values is still non-zero.
206+
unsafe {
207+
Self(self.0.min(other.0))
208+
}
209+
}
210+
211+
fn clamp(self, min: Self, max: Self) -> Self {
212+
#[allow(unused_unsafe)]
213+
// SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values, and
214+
// a non-zero value clamped between two non-zero values is still non-zero.
215+
unsafe {
216+
Self(self.0.clamp(min.0, max.0))
217+
}
218+
}
219+
}
220+
221+
#[$stability]
222+
impl Hash for $Ty {
223+
#[inline]
224+
fn hash<H>(&self, state: &mut H)
225+
where
226+
H: Hasher,
227+
{
228+
// SAFETY: A `NonZero` is guaranteed to only contain primitive non-zero values.
229+
#[allow(unused_unsafe)]
230+
unsafe {
231+
self.0.hash(state)
232+
}
233+
}
234+
}
235+
};
236+
}
237+
74238
macro_rules! impl_nonzero_fmt {
75239
( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
76240
$(
@@ -128,13 +292,15 @@ macro_rules! nonzero_integer {
128292
///
129293
/// [null pointer optimization]: crate::option#representation
130294
#[$stability]
131-
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
295+
#[derive(Copy, Eq)]
132296
#[repr(transparent)]
133297
#[rustc_layout_scalar_valid_range_start(1)]
134298
#[rustc_nonnull_optimization_guaranteed]
135299
#[rustc_diagnostic_item = stringify!($Ty)]
136300
pub struct $Ty($Int);
137301

302+
impl_nonzero_traits!(#[$stability] $Ty);
303+
138304
impl $Ty {
139305
/// Creates a non-zero without checking whether the value is non-zero.
140306
/// This results in undefined behaviour if the value is zero.

‎tests/ui/unsafe/ranged_ints3.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::cell::Cell;
55
#[rustc_layout_scalar_valid_range_start(1)]
66
#[repr(transparent)]
77
pub(crate) struct NonZero<T>(pub(crate) T);
8+
89
fn main() {
910
let mut x = unsafe { NonZero(Cell::new(1)) };
1011
let y = &x.0; //~ ERROR borrow of layout constrained field with interior mutability

‎tests/ui/unsafe/ranged_ints3_match.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::cell::Cell;
55
#[rustc_layout_scalar_valid_range_start(1)]
66
#[repr(transparent)]
77
pub(crate) struct NonZero<T>(pub(crate) T);
8+
89
fn main() {
910
let mut x = unsafe { NonZero(Cell::new(1)) };
1011
match x {

0 commit comments

Comments
 (0)
Please sign in to comment.