manifold3d_types/math/
positive_num.rs

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
use crate::math;
use std::cmp::Ordering;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum PositiveNumError {
    #[error("the value is not positive")]
    NonPositiveValue,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct PositiveNum<T: num_traits::Num + Clone + Copy + PartialOrd>(T);

impl<T: num_traits::Num + Copy + PartialOrd> PositiveNum<T> {
    pub fn new(value: T) -> Result<Self, math::PositiveNumError> {
        if !Self::is_valid(value) {
            return Err(math::PositiveNumError::NonPositiveValue);
        }
        Ok(PositiveNum(value))
    }

    #[inline(always)]
    fn is_valid(value: T) -> bool {
        value > T::zero()
    }
}

impl<T: num_traits::Num + PartialOrd + Copy> PositiveNum<T> {
    pub fn get(&self) -> T {
        self.0
    }
}

macro_rules! impl_positive_num_from {
    ($ttype:ident, $underlying_primitive:ident, ($($from_type:ty),+)) => {
        $(
            impl From<$from_type> for $ttype {
                fn from(value: $from_type) -> Self {
                    PositiveNum($underlying_primitive::from(value))
                }
            }
        )+
    };
}

macro_rules! impl_positive_num_try_from {
    ($ttype:ident, $underlying_primitive:ident, ($($from_type:ty),+)) => {
        $(
            impl TryFrom<$from_type> for $ttype {
                type Error = PositiveNumError;

                fn try_from(value: $from_type) -> Result<Self, Self::Error> {
                    $ttype::new($underlying_primitive::from(value))
                }
            }
        )+
    };
}

macro_rules! impl_into_primitive {
    ($ttype:ident, $underlying_primitive:ident) => {
        #[allow(clippy::from_over_into)]
        impl Into<$underlying_primitive> for $ttype {
            fn into(self) -> $underlying_primitive {
                self.get()
            }
        }
    };
}

macro_rules! impl_partial_eq {
    ($ttype:ident, $underlying_primitive:ident, ($($eq_type:ty),+)) => {
        $(
            impl PartialEq<$eq_type> for $ttype {
                fn eq(&self, other: &$eq_type) -> bool {
                    self.get().eq(&(*other as $underlying_primitive))
                }
            }
        )+
    };
}

macro_rules! impl_partial_ord {
    ($ttype:ident, $underlying_primitive:ident, ($($eq_type:ty),+)) => {
        $(
            impl PartialOrd<$eq_type> for $ttype {
                fn partial_cmp(&self, other: &$eq_type) -> Option<Ordering> {
                    self.get().partial_cmp(&(*other as $underlying_primitive))
                }
            }
        )+
    };
}

pub type PositiveI32 = PositiveNum<i32>;
impl_into_primitive!(PositiveI32, i32);
impl_positive_num_from!(PositiveI32, i32, (u8, u16));
impl_positive_num_try_from!(PositiveI32, i32, (i8, i16, i32));
impl_partial_eq!(PositiveI32, i32, (i8, i16, i32));
impl_partial_ord!(PositiveI32, i32, (i8, i16, i32));

pub type PositiveF64 = PositiveNum<f64>;
impl_into_primitive!(PositiveF64, f64);
impl_positive_num_from!(PositiveF64, f64, (u8, u16, u32));
impl_positive_num_try_from!(PositiveF64, f64, (i8, i16, i32, f32, f64));
impl_partial_eq!(PositiveF64, f64, (i8, i16, i32, f32, f64));
impl_partial_ord!(PositiveF64, f64, (i8, i16, i32, f32, f64));