Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use generic NonZero everywhere in library. #121454

Merged
merged 5 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions library/alloc/src/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use core::borrow::Borrow;
use core::ffi::{c_char, CStr};
use core::fmt;
use core::mem;
use core::num::NonZeroU8;
use core::num::NonZero;
use core::ops;
use core::ptr;
use core::slice;
Expand Down Expand Up @@ -795,22 +795,22 @@ impl From<Box<CStr>> for CString {
}

#[stable(feature = "cstring_from_vec_of_nonzerou8", since = "1.43.0")]
impl From<Vec<NonZeroU8>> for CString {
/// Converts a <code>[Vec]<[NonZeroU8]></code> into a [`CString`] without
impl From<Vec<NonZero<u8>>> for CString {
/// Converts a <code>[Vec]<[NonZero]<[u8]>></code> into a [`CString`] without
/// copying nor checking for inner nul bytes.
#[inline]
fn from(v: Vec<NonZeroU8>) -> CString {
fn from(v: Vec<NonZero<u8>>) -> CString {
unsafe {
// Transmute `Vec<NonZeroU8>` to `Vec<u8>`.
// Transmute `Vec<NonZero<u8>>` to `Vec<u8>`.
let v: Vec<u8> = {
// SAFETY:
// - transmuting between `NonZeroU8` and `u8` is sound;
// - `alloc::Layout<NonZeroU8> == alloc::Layout<u8>`.
let (ptr, len, cap): (*mut NonZeroU8, _, _) = Vec::into_raw_parts(v);
// - transmuting between `NonZero<u8>` and `u8` is sound;
// - `alloc::Layout<NonZero<u8>> == alloc::Layout<u8>`.
let (ptr, len, cap): (*mut NonZero<u8>, _, _) = Vec::into_raw_parts(v);
Vec::from_raw_parts(ptr.cast::<u8>(), len, cap)
};
// SAFETY: `v` cannot contain nul bytes, given the type-level
// invariant of `NonZeroU8`.
// invariant of `NonZero<u8>`.
Self::_from_vec_unchecked(v)
}
}
Expand Down
51 changes: 19 additions & 32 deletions library/alloc/src/vec/is_zero.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::num::{Saturating, Wrapping};
use core::num::{NonZero, Saturating, Wrapping};

use crate::boxed::Box;

Expand Down Expand Up @@ -69,7 +69,7 @@ unsafe impl<T: IsZero, const N: usize> IsZero for [T; N] {
}

// This is recursive macro.
macro_rules! impl_for_tuples {
macro_rules! impl_is_zero_tuples {
// Stopper
() => {
// No use for implementing for empty tuple because it is ZST.
Expand All @@ -88,11 +88,11 @@ macro_rules! impl_for_tuples {
}
}

impl_for_tuples!($($rest),*);
impl_is_zero_tuples!($($rest),*);
}
}

impl_for_tuples!(A, B, C, D, E, F, G, H);
impl_is_zero_tuples!(A, B, C, D, E, F, G, H);

// `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`
Expand All @@ -115,16 +115,15 @@ unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
}
}

// `Option<num::NonZeroU32>` and similar have a representation guarantee that
// `Option<NonZero<u32>>` 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.
// that transmuting between `NonZero<u32>` and `Option<NonZero<u32>>` 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> {
macro_rules! impl_is_zero_option_of_nonzero_int {
($($t:ty),+ $(,)?) => {$(
unsafe impl IsZero for Option<NonZero<$t>> {
#[inline]
fn is_zero(&self) -> bool {
self.is_none()
Expand All @@ -133,23 +132,10 @@ macro_rules! impl_is_zero_option_of_nonzero {
)+};
}

impl_is_zero_option_of_nonzero!(
NonZeroU8,
NonZeroU16,
NonZeroU32,
NonZeroU64,
NonZeroU128,
NonZeroI8,
NonZeroI16,
NonZeroI32,
NonZeroI64,
NonZeroI128,
NonZeroUsize,
NonZeroIsize,
);

macro_rules! impl_is_zero_option_of_num {
($($t:ty,)+) => {$(
impl_is_zero_option_of_nonzero_int!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);

macro_rules! impl_is_zero_option_of_int {
($($t:ty),+ $(,)?) => {$(
unsafe impl IsZero for Option<$t> {
#[inline]
fn is_zero(&self) -> bool {
Expand All @@ -163,7 +149,7 @@ macro_rules! impl_is_zero_option_of_num {
)+};
}

impl_is_zero_option_of_num!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize,);
impl_is_zero_option_of_int!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize);

unsafe impl<T: IsZero> IsZero for Wrapping<T> {
#[inline]
Expand All @@ -179,8 +165,8 @@ unsafe impl<T: IsZero> IsZero for Saturating<T> {
}
}

macro_rules! impl_for_optional_bool {
($($t:ty,)+) => {$(
macro_rules! impl_is_zero_option_of_bool {
($($t:ty),+ $(,)?) => {$(
unsafe impl IsZero for $t {
#[inline]
fn is_zero(&self) -> bool {
Expand All @@ -194,9 +180,10 @@ macro_rules! impl_for_optional_bool {
}
)+};
}
impl_for_optional_bool! {

impl_is_zero_option_of_bool! {
Option<bool>,
Option<Option<bool>>,
Option<Option<Option<bool>>>,
// Could go further, but not worth the metadata overhead
// Could go further, but not worth the metadata overhead.
}
10 changes: 5 additions & 5 deletions library/core/src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ impl<T, const N: usize> [T; N] {
/// # Examples
///
/// ```
/// #![feature(array_try_map)]
/// #![feature(array_try_map, generic_nonzero)]
/// let a = ["1", "2", "3"];
/// let b = a.try_map(|v| v.parse::<u32>()).unwrap().map(|v| v + 1);
/// assert_eq!(b, [2, 3, 4]);
Expand All @@ -520,12 +520,12 @@ impl<T, const N: usize> [T; N] {
/// let b = a.try_map(|v| v.parse::<u32>());
/// assert!(b.is_err());
///
/// use std::num::NonZeroU32;
/// use std::num::NonZero;
/// let z = [1, 2, 0, 3, 4];
/// assert_eq!(z.try_map(NonZeroU32::new), None);
/// assert_eq!(z.try_map(NonZero::new), None);
/// let a = [1, 2, 3];
/// let b = a.try_map(NonZeroU32::new);
/// let c = b.map(|x| x.map(NonZeroU32::get));
/// let b = a.try_map(NonZero::new);
/// let c = b.map(|x| x.map(NonZero::get));
/// assert_eq!(c, Some(a));
/// ```
#[unstable(feature = "array_try_map", issue = "79711")]
Expand Down
51 changes: 25 additions & 26 deletions library/core/src/cmp/bytewise.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
use crate::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
use crate::num::NonZero;

/// Types where `==` & `!=` are equivalent to comparing their underlying bytes.
///
Expand Down Expand Up @@ -36,37 +35,37 @@ is_bytewise_comparable!(bool, char, super::Ordering);
// SAFETY: Similarly, the `NonZero` type has a niche, but no undef and no pointers,
// and they compare like their underlying numeric type.
is_bytewise_comparable!(
NonZeroU8,
NonZeroU16,
NonZeroU32,
NonZeroU64,
NonZeroU128,
NonZeroUsize,
NonZeroI8,
NonZeroI16,
NonZeroI32,
NonZeroI64,
NonZeroI128,
NonZeroIsize,
NonZero<u8>,
NonZero<u16>,
NonZero<u32>,
NonZero<u64>,
NonZero<u128>,
NonZero<usize>,
NonZero<i8>,
NonZero<i16>,
NonZero<i32>,
NonZero<i64>,
NonZero<i128>,
NonZero<isize>,
);

// SAFETY: The `NonZero` type has the "null" optimization guaranteed, and thus
// are also safe to equality-compare bitwise inside an `Option`.
// The way `PartialOrd` is defined for `Option` means that this wouldn't work
// for `<` or `>` on the signed types, but since we only do `==` it's fine.
is_bytewise_comparable!(
Option<NonZeroU8>,
Option<NonZeroU16>,
Option<NonZeroU32>,
Option<NonZeroU64>,
Option<NonZeroU128>,
Option<NonZeroUsize>,
Option<NonZeroI8>,
Option<NonZeroI16>,
Option<NonZeroI32>,
Option<NonZeroI64>,
Option<NonZeroI128>,
Option<NonZeroIsize>,
Option<NonZero<u8>>,
Option<NonZero<u16>>,
Option<NonZero<u32>>,
Option<NonZero<u64>>,
Option<NonZero<u128>>,
Option<NonZero<usize>>,
Option<NonZero<i8>>,
Option<NonZero<i16>>,
Option<NonZero<i32>>,
Option<NonZero<i64>>,
Option<NonZero<i128>>,
Option<NonZero<isize>>,
);

macro_rules! is_bytewise_comparable_array_length {
Expand Down
8 changes: 4 additions & 4 deletions library/core/src/iter/traits/double_ended.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub trait DoubleEndedIterator: Iterator {
/// to `n` times until [`None`] is encountered.
///
/// `advance_back_by(n)` will return `Ok(())` if the iterator successfully advances by
/// `n` elements, or a `Err(NonZeroUsize)` with value `k` if [`None`] is encountered, where `k`
/// `n` elements, or a `Err(NonZero<usize>)` with value `k` if [`None`] is encountered, where `k`
/// is remaining number of steps that could not be advanced because the iterator ran out.
/// If `self` is empty and `n` is non-zero, then this returns `Err(n)`.
/// Otherwise, `k` is always less than `n`.
Expand All @@ -118,16 +118,16 @@ pub trait DoubleEndedIterator: Iterator {
/// Basic usage:
///
/// ```
/// #![feature(iter_advance_by)]
/// use std::num::NonZeroUsize;
/// #![feature(generic_nonzero, iter_advance_by)]
/// use std::num::NonZero;
///
/// let a = [3, 4, 5, 6];
/// let mut iter = a.iter();
///
/// assert_eq!(iter.advance_back_by(2), Ok(()));
/// assert_eq!(iter.next_back(), Some(&4));
/// assert_eq!(iter.advance_back_by(0), Ok(()));
/// assert_eq!(iter.advance_back_by(100), Err(NonZeroUsize::new(99).unwrap())); // only `&3` was skipped
/// assert_eq!(iter.advance_back_by(100), Err(NonZero::new(99).unwrap())); // only `&3` was skipped
/// ```
///
/// [`Ok(())`]: Ok
Expand Down
23 changes: 12 additions & 11 deletions library/core/src/iter/traits/iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ pub trait Iterator {
/// times until [`None`] is encountered.
///
/// `advance_by(n)` will return `Ok(())` if the iterator successfully advances by
/// `n` elements, or a `Err(NonZeroUsize)` with value `k` if [`None`] is encountered,
/// `n` elements, or a `Err(NonZero<usize>)` with value `k` if [`None`] is encountered,
/// where `k` is remaining number of steps that could not be advanced because the iterator ran out.
/// If `self` is empty and `n` is non-zero, then this returns `Err(n)`.
/// Otherwise, `k` is always less than `n`.
Expand All @@ -319,16 +319,16 @@ pub trait Iterator {
/// # Examples
///
/// ```
/// #![feature(iter_advance_by)]
/// use std::num::NonZeroUsize;
/// #![feature(generic_nonzero, iter_advance_by)]
/// use std::num::NonZero;
///
/// let a = [1, 2, 3, 4];
/// let mut iter = a.iter();
///
/// assert_eq!(iter.advance_by(2), Ok(()));
/// assert_eq!(iter.next(), Some(&3));
/// assert_eq!(iter.advance_by(0), Ok(()));
/// assert_eq!(iter.advance_by(100), Err(NonZeroUsize::new(99).unwrap())); // only `&4` was skipped
/// assert_eq!(iter.advance_by(100), Err(NonZero::new(99).unwrap())); // only `&4` was skipped
/// ```
#[inline]
#[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")]
Expand Down Expand Up @@ -2967,17 +2967,18 @@ pub trait Iterator {
/// assert!(result.is_err());
/// ```
///
/// This also supports other types which implement `Try`, not just `Result`.
/// This also supports other types which implement [`Try`], not just [`Result`].
///
/// ```
/// #![feature(try_find)]
/// #![feature(generic_nonzero, try_find)]
/// use std::num::NonZero;
///
/// use std::num::NonZeroU32;
/// let a = [3, 5, 7, 4, 9, 0, 11];
/// let result = a.iter().try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
/// let a = [3, 5, 7, 4, 9, 0, 11u32];
/// let result = a.iter().try_find(|&&x| NonZero::new(x).map(|y| y.is_power_of_two()));
/// assert_eq!(result, Some(Some(&4)));
/// let result = a.iter().take(3).try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
/// let result = a.iter().take(3).try_find(|&&x| NonZero::new(x).map(|y| y.is_power_of_two()));
/// assert_eq!(result, Some(None));
/// let result = a.iter().rev().try_find(|&&x| NonZeroU32::new(x).map(|y| y.is_power_of_two()));
/// let result = a.iter().rev().try_find(|&&x| NonZero::new(x).map(|y| y.is_power_of_two()));
/// assert_eq!(result, None);
/// ```
#[inline]
Expand Down
16 changes: 7 additions & 9 deletions library/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ mod private {

/// A marker trait for primitive types which can be zero.
///
/// This is an implementation detail for [`NonZero<T>`](NonZero) which may disappear or be replaced at any time.
/// This is an implementation detail for <code>[NonZero]\<T></code> which may disappear or be replaced at any time.
#[unstable(
feature = "nonzero_internals",
reason = "implementation detail which may disappear or be replaced at any time",
Expand Down Expand Up @@ -507,18 +507,16 @@ macro_rules! nonzero_integer {
/// Basic usage:
///
/// ```
/// #![feature(non_zero_count_ones)]
/// #![feature(generic_nonzero, non_zero_count_ones)]
/// # fn main() { test().unwrap(); }
/// # fn test() -> Option<()> {
/// # use std::num::*;
/// #
/// let one = NonZeroU32::new(1)?;
/// let three = NonZeroU32::new(3)?;
#[doc = concat!("let a = ", stringify!($Ty), "::new(0b100_0000)?;")]
#[doc = concat!("let b = ", stringify!($Ty), "::new(0b100_0011)?;")]
#[doc = concat!("let a = NonZero::<", stringify!($Int), ">::new(0b100_0000)?;")]
#[doc = concat!("let b = NonZero::<", stringify!($Int), ">::new(0b100_0011)?;")]
///
/// assert_eq!(a.count_ones(), one);
/// assert_eq!(b.count_ones(), three);
/// assert_eq!(a.count_ones(), NonZero::new(1)?);
/// assert_eq!(b.count_ones(), NonZero::new(3)?);
/// # Some(())
/// # }
/// ```
Expand All @@ -530,7 +528,7 @@ macro_rules! nonzero_integer {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline(always)]
pub const fn count_ones(self) -> NonZeroU32 {
pub const fn count_ones(self) -> NonZero<u32> {
// SAFETY:
// `self` is non-zero, which means it has at least one bit set, which means
// that the result of `count_ones` is non-zero.
Expand Down
Loading
Loading