smallrand 1.1.0

Random number generation with absolutely minimal dependencies and no unsafe code.
Documentation
use core::ops::{Bound, Range, RangeBounds};

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct GenerateRange<T> {
    pub start: T,
    pub end_inclusive: T,
}

macro_rules! from_range_bounds {
    ($value_type: ty) => {
        impl<R> From<R> for GenerateRange<$value_type>
        where
            R: RangeBounds<$value_type>,
        {
            #[inline(always)]
            fn from(range: R) -> Self {
                Self {
                    start: match range.start_bound() {
                        Bound::Included(start) => *start,
                        Bound::Excluded(start) => {
                            start.checked_add(1).expect("Range start overflow")
                        }
                        Bound::Unbounded => <$value_type>::MIN,
                    },
                    end_inclusive: match range.end_bound() {
                        Bound::Included(end) => *end,
                        Bound::Excluded(end) => end.checked_sub(1).expect("Range end underflow"),
                        Bound::Unbounded => <$value_type>::MAX,
                    },
                }
            }
        }
    };
}

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

macro_rules! from_range {
    ($value_type: ty) => {
        impl From<Range<$value_type>> for GenerateRange<$value_type> {
            #[inline(always)]
            fn from(range: Range<$value_type>) -> Self {
                Self {
                    start: range.start,
                    end_inclusive: range.end,
                }
            }
        }
    };
}

from_range!(f32);
from_range!(f64);

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn integer_conversions() {
        fn to_range(range: impl RangeBounds<u8>) -> GenerateRange<u8> {
            range.into()
        }

        assert_eq!(
            GenerateRange {
                start: 2_u8,
                end_inclusive: 41
            },
            to_range(2..42)
        );
        assert_eq!(
            GenerateRange {
                start: u8::MIN,
                end_inclusive: 42
            },
            to_range(..=42)
        );
        assert_eq!(
            GenerateRange {
                start: u8::MIN,
                end_inclusive: u8::MAX
            },
            to_range(..)
        );
    }

    #[test]
    fn float_conversions() {
        fn to_range(range: Range<f64>) -> GenerateRange<f64> {
            range.into()
        }

        assert_eq!(
            GenerateRange {
                start: 2_f64,
                end_inclusive: 42_f64
            },
            to_range(2.0..42.0)
        );
    }
}