nonzero_ext/lib.rs
1//! # Traits to represent generic nonzero integer types
2//! [](https://travis-ci.com/antifuchs/nonzero_ext) [](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}