manifold3d_types/math/
positive_num.rs1use crate::math;
2use std::cmp::Ordering;
3use thiserror::Error;
4
5#[derive(Error, Debug)]
6pub enum PositiveNumError {
7 #[error("the value is not positive")]
8 NonPositiveValue,
9}
10
11#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
12pub struct PositiveNum<T: num_traits::Num + Clone + Copy + PartialOrd>(T);
13
14impl<T: num_traits::Num + Copy + PartialOrd> PositiveNum<T> {
15 pub fn new(value: T) -> Result<Self, math::PositiveNumError> {
16 if !Self::is_valid(value) {
17 return Err(math::PositiveNumError::NonPositiveValue);
18 }
19 Ok(PositiveNum(value))
20 }
21
22 #[inline(always)]
23 fn is_valid(value: T) -> bool {
24 value > T::zero()
25 }
26}
27
28impl<T: num_traits::Num + PartialOrd + Copy> PositiveNum<T> {
29 pub fn get(&self) -> T {
30 self.0
31 }
32}
33
34macro_rules! impl_positive_num_from {
35 ($ttype:ident, $underlying_primitive:ident, ($($from_type:ty),+)) => {
36 $(
37 impl From<$from_type> for $ttype {
38 fn from(value: $from_type) -> Self {
39 PositiveNum($underlying_primitive::from(value))
40 }
41 }
42 )+
43 };
44}
45
46macro_rules! impl_positive_num_try_from {
47 ($ttype:ident, $underlying_primitive:ident, ($($from_type:ty),+)) => {
48 $(
49 impl TryFrom<$from_type> for $ttype {
50 type Error = PositiveNumError;
51
52 fn try_from(value: $from_type) -> Result<Self, Self::Error> {
53 $ttype::new($underlying_primitive::from(value))
54 }
55 }
56 )+
57 };
58}
59
60macro_rules! impl_into_primitive {
61 ($ttype:ident, $underlying_primitive:ident) => {
62 #[allow(clippy::from_over_into)]
63 impl Into<$underlying_primitive> for $ttype {
64 fn into(self) -> $underlying_primitive {
65 self.get()
66 }
67 }
68 };
69}
70
71macro_rules! impl_partial_eq {
72 ($ttype:ident, $underlying_primitive:ident, ($($eq_type:ty),+)) => {
73 $(
74 impl PartialEq<$eq_type> for $ttype {
75 fn eq(&self, other: &$eq_type) -> bool {
76 self.get().eq(&(*other as $underlying_primitive))
77 }
78 }
79 )+
80 };
81}
82
83macro_rules! impl_partial_ord {
84 ($ttype:ident, $underlying_primitive:ident, ($($eq_type:ty),+)) => {
85 $(
86 impl PartialOrd<$eq_type> for $ttype {
87 fn partial_cmp(&self, other: &$eq_type) -> Option<Ordering> {
88 self.get().partial_cmp(&(*other as $underlying_primitive))
89 }
90 }
91 )+
92 };
93}
94
95pub type PositiveI32 = PositiveNum<i32>;
96impl_into_primitive!(PositiveI32, i32);
97impl_positive_num_from!(PositiveI32, i32, (u8, u16));
98impl_positive_num_try_from!(PositiveI32, i32, (i8, i16, i32));
99impl_partial_eq!(PositiveI32, i32, (i8, i16, i32));
100impl_partial_ord!(PositiveI32, i32, (i8, i16, i32));
101
102pub type PositiveF64 = PositiveNum<f64>;
103impl_into_primitive!(PositiveF64, f64);
104impl_positive_num_from!(PositiveF64, f64, (u8, u16, u32));
105impl_positive_num_try_from!(PositiveF64, f64, (i8, i16, i32, f32, f64));
106impl_partial_eq!(PositiveF64, f64, (i8, i16, i32, f32, f64));
107impl_partial_ord!(PositiveF64, f64, (i8, i16, i32, f32, f64));