nonzero_ext/
lib.rs

1//! # Traits to represent generic nonzero integer types
2//! [![Build Status](https://travis-ci.com/antifuchs/nonzero_ext.svg?branch=master)](https://travis-ci.com/antifuchs/nonzero_ext) [![Docs](https://docs.rs/nonzero_ext/badge.svg)](https://docs.rs/nonzero_ext)
3//!
4//! Rust ships with non-zero integer types now, which let programmers
5//! promise (memory-savingly!) that a number can never be zero. That's
6//! great, but sadly the standard library has not got a whole lot of
7//! tools to help you use them ergonomically.
8//!
9//! ## A macro for non-zero constant literals
10//!
11//! Creating and handling constant literals is neat, but the standard
12//! library (and the rust parser at the moment) have no affordances to
13//! easily create values of `num::NonZeroU*` types from constant
14//! literals. This crate ships a `nonzero!` macro that lets you write
15//! `nonzero!(20u32)`, which checks at compile time that the constant
16//! being converted is non-zero, instead of the cumbersome (and
17//! runtime-checked!)  `NonZeroU32::new(20).unwrap()`.
18//!
19//! ## Traits for generic non-zeroness
20//!
21//! The stdlib `num::NonZeroU*` types do not implement any common
22//! traits (and neither do their zeroable equivalents).  Where this
23//! lack of traits in the standard library becomes problematic is if
24//! you want to write a function that takes a vector of integers, and
25//! that returns a vector of the corresponding non-zero integer types,
26//! minus any elements that were zero in the original. You can write
27//! that with the standard library quite easily for concrete types:
28//!
29//! ```rust
30//! # use std::num::NonZeroU8;
31//! fn only_nonzeros(v: Vec<u8>) -> Vec<NonZeroU8>
32//! {
33//!     v.into_iter()
34//!         .filter_map(|n| NonZeroU8::new(n))
35//!         .collect::<Vec<NonZeroU8>>()
36//! }
37//! # #[macro_use] extern crate nonzero_ext;
38//! # fn main() {
39//! let expected: Vec<NonZeroU8> = vec![nonzero!(20u8), nonzero!(5u8)];
40//! assert_eq!(expected, only_nonzeros(vec![0, 20, 5]));
41//! # }
42//! ```
43//!
44//! But what if you want to allow this function to work with any
45//! integer type that has a corresponding non-zero type? This crate
46//! can help:
47//!
48//! ```rust
49//! # use std::num::{NonZeroU8, NonZeroU32};
50//! # use nonzero_ext::{NonZeroAble};
51//! fn only_nonzeros<I>(v: Vec<I>) -> Vec<I::NonZero>
52//! where
53//!     I: Sized + NonZeroAble,
54//! {
55//!     v.into_iter()
56//!         .filter_map(|n| n.as_nonzero())
57//!         .collect::<Vec<I::NonZero>>()
58//! }
59//!
60//! # #[macro_use] extern crate nonzero_ext;
61//! # fn main() {
62//! // It works for `u8`:
63//! let input_u8: Vec<u8> = vec![0, 20, 5];
64//! let expected_u8: Vec<NonZeroU8> = vec![nonzero!(20u8), nonzero!(5u8)];
65//! assert_eq!(expected_u8, only_nonzeros(input_u8));
66//!
67//! // And it works for `u32`:
68//! let input_u32: Vec<u32> = vec![0, 20, 5];
69//! let expected_u32: Vec<NonZeroU32> = vec![nonzero!(20u32), nonzero!(5u32)];
70//! assert_eq!(expected_u32, only_nonzeros(input_u32));
71//! # }
72//! ```
73//!
74
75#![cfg_attr(not(feature = "std"), no_std)]
76#![allow(unknown_lints)]
77// Unfortunately necessary, otherwise features aren't supported in doctests:
78#![allow(clippy::needless_doctest_main)]
79
80mod lib {
81    mod core {
82        #[cfg(feature = "std")]
83        pub use std::*;
84
85        #[cfg(not(feature = "std"))]
86        pub use core::*;
87    }
88    pub use self::core::num::{
89        NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize,
90    };
91    pub use self::core::num::{
92        NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize,
93    };
94}
95
96use self::lib::*;
97
98pub mod literals;
99
100macro_rules! impl_nonzeroness {
101    ($trait_name:ident, $nonzero_type:ty, $wrapped:ty) => {
102        impl $trait_name for $nonzero_type {
103            type Primitive = $wrapped;
104
105            #[inline]
106            #[cfg_attr(feature = "cargo-clippy", allow(clippy::new_ret_no_self))]
107            fn new(n: $wrapped) -> Option<Self> {
108                Self::new(n)
109            }
110
111            #[inline]
112            fn get(self) -> Self::Primitive {
113                <$nonzero_type>::get(self)
114            }
115        }
116    };
117}
118
119/// A trait identifying a non-zero integral type. It is useful mostly
120/// in order to give to genericized helper functions as `impl NonZero`
121/// arguments.
122pub trait NonZero {
123    /// The primitive type (e.g. `u8`) underlying this integral type.
124    type Primitive;
125
126    /// Creates a new non-zero object from an integer that might be
127    /// zero.
128    fn new(n: Self::Primitive) -> Option<Self>
129    where
130        Self: Sized;
131
132    /// Returns the value as a primitive type.
133    fn get(self) -> Self::Primitive;
134}
135
136impl_nonzeroness!(NonZero, NonZeroU8, u8);
137impl_nonzeroness!(NonZero, NonZeroU16, u16);
138impl_nonzeroness!(NonZero, NonZeroU32, u32);
139impl_nonzeroness!(NonZero, NonZeroU64, u64);
140impl_nonzeroness!(NonZero, NonZeroU128, u128);
141impl_nonzeroness!(NonZero, NonZeroUsize, usize);
142
143impl_nonzeroness!(NonZero, NonZeroI8, i8);
144impl_nonzeroness!(NonZero, NonZeroI16, i16);
145impl_nonzeroness!(NonZero, NonZeroI32, i32);
146impl_nonzeroness!(NonZero, NonZeroI64, i64);
147impl_nonzeroness!(NonZero, NonZeroI128, i128);
148impl_nonzeroness!(NonZero, NonZeroIsize, isize);
149
150/// A trait identifying integral types that have a non-zeroable
151/// equivalent.
152pub trait NonZeroAble {
153    /// The concrete non-zero type represented by an implementation of
154    /// this trait. For example, for `u8`'s implementation, it is
155    /// `NonZeroU8`.
156    type NonZero: NonZero;
157
158    //noinspection RsSelfConvention
159    /// Converts the integer to its non-zero equivalent.
160    ///
161    /// # Examples
162    ///
163    /// ### Trying to convert zero
164    /// ``` rust
165    /// # use nonzero_ext::NonZeroAble;
166    /// let n: u16 = 0;
167    /// assert_eq!(n.as_nonzero(), None);
168    /// ```
169    ///
170    /// ### Converting a non-zero value
171    /// ``` rust
172    /// # use nonzero_ext::NonZeroAble;
173    /// # use std::num::NonZeroUsize;
174    /// let n: usize = 20;
175    /// let non0n: NonZeroUsize = n.as_nonzero().expect("should result in a converted value");
176    /// assert_eq!(non0n.get(), 20);
177    /// ```
178    #[deprecated(since = "0.2.0", note = "Renamed to `into_nonzero`")]
179    #[allow(clippy::wrong_self_convention)]
180    fn as_nonzero(self) -> Option<Self::NonZero>
181    where
182        Self: Sized,
183    {
184        self.into_nonzero()
185    }
186
187    /// Converts the integer to its non-zero equivalent.
188    ///
189    /// # Examples
190    ///
191    /// ### Trying to convert zero
192    /// ``` rust
193    /// # use nonzero_ext::NonZeroAble;
194    /// let n: u16 = 0;
195    /// assert_eq!(n.into_nonzero(), None);
196    /// ```
197    ///
198    /// ### Converting a non-zero value
199    /// ``` rust
200    /// # use nonzero_ext::NonZeroAble;
201    /// # use std::num::NonZeroUsize;
202    /// let n: usize = 20;
203    /// let non0n: NonZeroUsize = n.into_nonzero().expect("should result in a converted value");
204    /// assert_eq!(non0n.get(), 20);
205    /// ```
206    fn into_nonzero(self) -> Option<Self::NonZero>;
207
208    //noinspection RsSelfConvention
209    /// Converts the integer to its non-zero equivalent without
210    /// checking for zeroness.
211    ///
212    /// This corresponds to the `new_unchecked` function on the
213    /// corresponding NonZero type.
214    ///
215    /// # Safety
216    /// The value must not be zero.
217    #[deprecated(since = "0.2.0", note = "Renamed to `into_nonzero_unchecked`")]
218    #[allow(clippy::wrong_self_convention)]
219    unsafe fn as_nonzero_unchecked(self) -> Self::NonZero
220    where
221        Self: Sized,
222    {
223        self.into_nonzero_unchecked()
224    }
225
226    /// Converts the integer to its non-zero equivalent without
227    /// checking for zeroness.
228    ///
229    /// This corresponds to the `new_unchecked` function on the
230    /// corresponding NonZero type.
231    ///
232    /// # Safety
233    /// The value must not be zero.
234    unsafe fn into_nonzero_unchecked(self) -> Self::NonZero;
235}
236
237macro_rules! impl_nonzeroable {
238    ($trait_name:ident, $nonzero_type: ty, $nonzeroable_type:ty) => {
239        impl $trait_name for $nonzeroable_type {
240            type NonZero = $nonzero_type;
241
242            fn into_nonzero(self) -> Option<$nonzero_type> {
243                Self::NonZero::new(self)
244            }
245
246            unsafe fn into_nonzero_unchecked(self) -> $nonzero_type {
247                Self::NonZero::new_unchecked(self)
248            }
249        }
250        impl literals::NonZeroLiteral<$nonzeroable_type> {
251            /// Converts the wrapped value to its non-zero equivalent.
252            /// # Safety
253            /// The wrapped value must be non-zero.
254            pub const unsafe fn into_nonzero(self) -> $nonzero_type {
255                <$nonzero_type>::new_unchecked(self.0)
256            }
257        }
258        impl literals::sealed::IntegerLiteral for $nonzeroable_type {}
259    };
260}
261
262impl_nonzeroable!(NonZeroAble, NonZeroU8, u8);
263impl_nonzeroable!(NonZeroAble, NonZeroU16, u16);
264impl_nonzeroable!(NonZeroAble, NonZeroU32, u32);
265impl_nonzeroable!(NonZeroAble, NonZeroU64, u64);
266impl_nonzeroable!(NonZeroAble, NonZeroU128, u128);
267impl_nonzeroable!(NonZeroAble, NonZeroUsize, usize);
268
269impl_nonzeroable!(NonZeroAble, NonZeroI8, i8);
270impl_nonzeroable!(NonZeroAble, NonZeroI16, i16);
271impl_nonzeroable!(NonZeroAble, NonZeroI32, i32);
272impl_nonzeroable!(NonZeroAble, NonZeroI64, i64);
273impl_nonzeroable!(NonZeroAble, NonZeroI128, i128);
274impl_nonzeroable!(NonZeroAble, NonZeroIsize, isize);
275
276/// Create non-zero values from constant literals easily.
277///
278/// This macro issues a compile-time check and, if it passes, creates
279/// the corresponding non-zero numeric value from the given
280/// constant. Since the type of constant literals needs to be exactly
281/// known, `nonzero!` requires that you annotate the constant with the
282/// type, so instead of `nonzero!(20)` you must write `nonzero!(20 as
283/// u16)`.
284///
285/// Note that this macro only works with [integer
286/// literals](https://doc.rust-lang.org/reference/tokens.html#integer-literals),
287/// it isn't possible to use the `nonzero!` macro with types other
288/// than the built-in ones.
289///
290/// # Determining the output type
291///
292/// Use a suffix on the input value to determine the output type:
293/// `nonzero!(1_usize)` will return a [`NonZeroUsize`], and
294/// `nonzero!(-1_i32)` will return a [`NonZeroI32`].
295///
296/// # Const expressions
297///
298/// This macro can be used in const expressions.
299///
300/// # Examples
301/// ```
302/// # #[macro_use]
303/// # extern crate nonzero_ext;
304/// # fn main() {
305/// nonzero!(20usize);  // => NonZeroUsize
306/// nonzero!(20u32);    // => NonZeroU32
307/// nonzero!(20 as u8); // => NonZeroU8
308/// # }
309/// ```
310///
311/// and passing a zero of any type will fail:
312///
313/// ``` # compile_fail
314/// # #[macro_use]
315/// # extern crate nonzero_ext;
316/// # fn main() {
317/// nonzero!(0u8);
318/// # }
319/// ```
320///
321#[macro_export]
322macro_rules! nonzero {
323    ($n:expr) => {{
324        #[allow(unknown_lints, eq_op)]
325        let _ = [(); ($n.count_ones() as usize) - 1];
326        let lit = $crate::literals::NonZeroLiteral($n);
327        unsafe { lit.into_nonzero() }
328    }};
329}