1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! # Traits to represent generic nonzero integer types
//! [![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)
//!
//! Rust ships with non-zero integer types now, which let programmers
//! promise (memory-savingly!) that a number can never be zero. That's
//! great, but sadly the standard library has no traits you can use to
//! represent all the non-zero integer types.
//!
//! # Examples
//!
//! Where this lack of traits in the standard library becomes
//! problematic is if you want to write a function that takes a vector
//! of integers, and that returns a vector of the corresponding
//! non-zero integer types, minus any elements that were zero in the
//! original. You can write that with the standard library quite
//! easily for concrete types:
//!
//! ```rust
//! # use std::num::NonZeroU8;
//! fn only_nonzeros(v: Vec<u8>) -> Vec<NonZeroU8>
//! {
//!     v.into_iter()
//!         .filter_map(|n| NonZeroU8::new(n))
//!         .collect::<Vec<NonZeroU8>>()
//! }
//! let expected: Vec<NonZeroU8> = vec![NonZeroU8::new(20).unwrap(), NonZeroU8::new(5).unwrap()];
//! assert_eq!(expected, only_nonzeros(vec![0, 20, 5]));
//! ```
//!
//! But what if you want to allow this function to work with any
//! integer type that has a corresponding non-zero type? This crate
//! can help:
//!
//! ```rust
//! # use std::num::{NonZeroU8, NonZeroU32};
//! # use nonzero_ext::{NonZeroAble};
//! fn only_nonzeros<I>(v: Vec<I>) -> Vec<I::NonZero>
//! where
//!     I: Sized + NonZeroAble,
//! {
//!     v.into_iter()
//!         .filter_map(|n| n.as_nonzero())
//!         .collect::<Vec<I::NonZero>>()
//! }
//!
//! // It works for `u8`:
//! let input_u8: Vec<u8> = vec![0, 20, 5];
//! let expected_u8: Vec<NonZeroU8> = vec![NonZeroU8::new(20).unwrap(), NonZeroU8::new(5).unwrap()];
//! assert_eq!(expected_u8, only_nonzeros(input_u8));
//!
//! // And it works for `u32`:
//! let input_u32: Vec<u32> = vec![0, 20, 5];
//! let expected_u32: Vec<NonZeroU32> = vec![NonZeroU32::new(20).unwrap(), NonZeroU32::new(5).unwrap()];
//! assert_eq!(expected_u32, only_nonzeros(input_u32));
//! ```
//!

use std::num::NonZeroUsize;
use std::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8};

macro_rules! impl_nonzeroness {
    ($trait_name:ident, $nonzero_type:ty, $wrapped:ty) => {
        impl $trait_name for $nonzero_type {
            type Primitive = $wrapped;

            #[inline]
            fn new(n: $wrapped) -> Option<Self> {
                Self::new(n)
            }

            #[inline]
            fn get(self) -> Self::Primitive {
                <$nonzero_type>::get(self)
            }
        }
    };
}

/// A trait identifying a non-zero integral type. It is useful mostly
/// in order to give to genericized helper functions as `impl NonZero`
/// arguments.
pub trait NonZero {
    /// The primitive type (e.g. `u8`) underlying this integral type.
    type Primitive;

    /// Creates a new non-zero object from an integer that might be
    /// zero.
    fn new(n: Self::Primitive) -> Option<Self>
    where
        Self: Sized;

    /// Returns the value as a primitive type.
    fn get(self) -> Self::Primitive;
}

impl_nonzeroness!(NonZero, NonZeroU8, u8);
impl_nonzeroness!(NonZero, NonZeroU16, u16);
impl_nonzeroness!(NonZero, NonZeroU32, u32);
impl_nonzeroness!(NonZero, NonZeroU64, u64);
impl_nonzeroness!(NonZero, NonZeroU128, u128);
impl_nonzeroness!(NonZero, NonZeroUsize, usize);

/// A trait identifying integral types that have a non-zeroable
/// equivalent.
pub trait NonZeroAble {
    /// The concrete non-zero type represented by an implementation of
    /// this trait. For example, for `u8`'s implementation, it is
    /// `NonZeroU8`.
    type NonZero: NonZero;

    /// Converts the integer to its non-zero equivalent.
    ///
    /// # Examples
    ///
    /// ### Trying to convert zero
    /// ``` rust
    /// # use nonzero_ext::NonZeroAble;
    /// let n: u16 = 0;
    /// assert_eq!(n.as_nonzero(), None);
    /// ```
    ///
    /// ### Converting a non-zero value
    /// ``` rust
    /// # use nonzero_ext::NonZeroAble;
    /// # use std::num::NonZeroUsize;
    /// let n: usize = 20;
    /// let non0n: NonZeroUsize = n.as_nonzero().expect("should result in a converted value");
    /// assert_eq!(non0n.get(), 20);
    /// ```
    fn as_nonzero(self) -> Option<Self::NonZero>;
}

macro_rules! impl_nonzeroable {
    ($trait_name:ident, $nonzero_type: ty, $nonzeroable_type:ty) => {
        impl $trait_name for $nonzeroable_type {
            type NonZero = $nonzero_type;

            fn as_nonzero(self) -> Option<$nonzero_type> {
                Self::NonZero::new(self)
            }
        }
    };
}

impl_nonzeroable!(NonZeroAble, NonZeroU8, u8);
impl_nonzeroable!(NonZeroAble, NonZeroU16, u16);
impl_nonzeroable!(NonZeroAble, NonZeroU32, u32);
impl_nonzeroable!(NonZeroAble, NonZeroU64, u64);
impl_nonzeroable!(NonZeroAble, NonZeroU128, u128);
impl_nonzeroable!(NonZeroAble, NonZeroUsize, usize);