derive_num_bounded/
lib.rs1#![allow(unused_macros)]
2#![allow(unused_imports)]
3
4pub use paste;
7pub use thiserror;
8
9#[macro_export]
10macro_rules! derive_new_from_bounded_partial_ord {
11 ( $type:ident < $a:ty : $bound:ident > ) => {
12 $crate::_derive_new_from_bounded_partial_ord!(
13 $type<$a: $bound>,
14 $a,
15 IsIncomparable,
16 "incomparable"
17 );
18 };
19 ( $type:ident {( $inner:ty )} ) => {
20 $crate::_derive_new_from_bounded_partial_ord!(
21 $type,
22 $inner,
23 IsIncomparable,
24 "incomparable"
25 );
26 };
27}
28
29#[macro_export]
30macro_rules! derive_new_from_bounded_float {
31 ( $type:ident < $a:ty : $bound:ident > ) => {
32 $crate::_derive_new_from_bounded_partial_ord!($type<$a: $bound>, $a, IsNan, "NaN");
33 };
34 ( $type:ident ( $inner:ty ) ) => {
35 $crate::_derive_new_from_bounded_partial_ord!($type, $inner, IsNan, "NaN");
36 };
37}
38
39#[macro_export]
40macro_rules! _derive_new_from_bounded_partial_ord {
41 ( $type:ident $( < $a:ty : $bound:ident > )?, $inner:ty, $incomparable_name:ident, $incomparable_str:literal ) => {
42 $crate::paste::paste! {
43 #[doc = "Error returned when '" $type "' is given an invalid value."]
44 #[derive(Clone, Copy, Debug, $crate::thiserror::Error, PartialEq)]
45 pub enum [<Invalid $type Error>] $(< $a : $bound >)? {
46 #[doc = "Value is " $incomparable_str "."]
47 #[error("{0} is {}", $incomparable_str)]
48 $incomparable_name($inner),
49 #[error("{0} is below lower bound ({})", < $type $(< $a >)? > ::min_value())]
51 TooLow($inner),
52 #[error("{0} is above upper bound ({})", < $type $(< $a >)? > ::max_value())]
54 TooHigh($inner),
55 }
56
57 impl $(< $a : $bound >)? $type $(< $a >)? {
58 #[doc = "Return a new '" $type "' if given a valid value."]
59 pub fn new(value: $inner) -> Result<Self, [<Invalid $type Error>] $(< $a >)? > {
60 match (
61 Self(value).partial_cmp(&Self::min_value()),
62 Self(value).partial_cmp(&Self::max_value()),
63 ) {
64 (None, _) | (_, None) => Err([<Invalid $type Error>]::$incomparable_name(value)),
65 (Some(std::cmp::Ordering::Less), _) => Err([<Invalid $type Error>]::TooLow(value)),
66 (_, Some(std::cmp::Ordering::Greater)) => Err([<Invalid $type Error>]::TooHigh(value)),
67 _ => Ok(Self(value)),
68 }
69 }
70 }
71 }
72 };
73}
74
75#[macro_export]
76macro_rules! derive_new_from_lower_bounded_partial_ord {
77 ( $type:ident < $a:ty : $bound:ident > ) => {
78 $crate::_derive_new_from_lower_bounded_partial_ord!(
79 $type<$a: $bound>,
80 $a,
81 IsIncomparable,
82 "incomparable"
83 );
84 };
85 ( $type:ident {( $inner:ty )} ) => {
86 $crate::_derive_new_from_lower_bounded_partial_ord!(
87 $type,
88 $inner,
89 IsIncomparable,
90 "incomparable"
91 );
92 };
93}
94
95#[macro_export]
96macro_rules! derive_new_from_lower_bounded_float {
97 ( $type:ident < $a:ty : $bound:ident > ) => {
98 $crate::_derive_new_from_lower_bounded_partial_ord!($type<$a: $bound>, $a, IsNan, "NaN");
99 };
100 ( $type:ident ( $inner:ty ) ) => {
101 $crate::_derive_new_from_lower_bounded_partial_ord!($type, $inner, IsNan, "NaN");
102 };
103}
104
105#[macro_export]
106macro_rules! _derive_new_from_lower_bounded_partial_ord {
107 ( $type:ident $( < $a:ty : $bound:ident > )?, $inner:ty, $incomparable_name:ident, $incomparable_str:literal ) => {
108 $crate::paste::paste! {
109 #[doc = "Error returned when '" $type "' is given an invalid value."]
110 #[derive(Clone, Copy, Debug, $crate::thiserror::Error, PartialEq, Eq)]
111 pub enum [<Invalid $type Error>] $(< $a : $bound >)? {
112 #[doc = "Value is " $incomparable_str "."]
113 #[error("{0} is {}", $incomparable_str)]
114 $incomparable_name($inner),
115 #[error("{0} is below lower bound ({})", < $type $(< $a >)? > ::min_value())]
117 TooLow($inner),
118 }
119
120 impl $(< $a : $bound >)? $type $(< $a >)? {
121 #[doc = "Return a new '" $type "' if given a valid value."]
122 pub fn new(value: $inner) -> Result<Self, [<Invalid $type Error>] $(< $a >)? > {
123 match Self(value).partial_cmp(&Self::min_value()) {
124 None => Err([<Invalid $type Error>]::$incomparable_name(value)),
125 Some(std::cmp::Ordering::Less) => Err([<Invalid $type Error>]::TooLow(value)),
126 _ => Ok(Self(value)),
127 }
128 }
129 }
130 }
131 };
132}
133
134#[macro_export]
135macro_rules! derive_new_from_lower_bounded {
136 ( $type:ident ( $inner: ty ) ) => {
137 $crate::paste::paste! {
138 #[doc = "Error returned when '" $type "' is given a value below lower bound."]
139 #[derive(Clone, Copy, Debug, $crate::thiserror::Error)]
140 #[error("{0} is below lower bound ({})", $type::min_value())]
141 pub struct [<Invalid $type Error>]($inner);
142
143 impl $type {
144 #[doc = "Return a new '" $type "' if given a valid value."]
145 pub fn new(value: $inner) -> Result<Self, [<Invalid $type Error>]> {
146 if Self(value) < Self::min_value() {
147 Err([<Invalid $type Error>](value))
148 } else {
149 Ok(Self(value))
150 }
151 }
152 }
153 }
154 };
155}
156
157#[macro_export]
158macro_rules! derive_try_from_from_new {
159 ( $type:ident ( $inner:ty ) ) => {
160 $crate::paste::paste! {
161 impl core::convert::TryFrom<$inner> for $type {
162 type Error = [<Invalid $type Error>];
163 fn try_from(value: $inner) -> Result<Self, Self::Error> {
164 $type::new(value)
165 }
166 }
167 }
168 };
169}
170
171#[macro_export]
172macro_rules! derive_from_str_from_try_into {
173 ( $type:ident ( $inner:ty ) ) => {
174 $crate::paste::paste! {
175 #[doc = "Error returned when failing to convert from a string or into '" $type "'."]
176 #[derive(Clone, Debug, $crate::thiserror::Error)]
177 #[error(transparent)]
178 pub struct [<$type FromStrError>](#[from] [<_ $type FromStrError>]);
179
180 #[derive(Clone, Debug, $crate::thiserror::Error)]
181 enum [<_ $type FromStrError>] {
182 #[doc = "Error convering from 'str' to '" $inner "'."]
183 #[error("Failed to convert from 'str': {0}")]
184 FromStr(<$inner as std::str::FromStr>::Err),
185 #[doc = "Error convering from '" $inner "' to '" $type "'."]
186 #[error("Failed to convert into type: {0}")]
187 TryInto(<$type as TryFrom<$inner>>::Error),
188 }
189
190 impl std::str::FromStr for $type {
191 type Err = [<$type FromStrError>];
192
193 fn from_str(s: &str) -> Result<Self, Self::Err> {
194 s.parse::<$inner>()
195 .map_err([<_ $type FromStrError>]::FromStr)
196 .and_then(|x| x.try_into().map_err([<_ $type FromStrError>]::TryInto))
197 .map_err(|x| x.into())
198 }
199 }
200 }
201 };
202}
203
204#[macro_export]
205macro_rules! derive_into_inner {
206 ( $type:ident ( $inner:ty ) ) => {
207 $crate::paste::paste! {
208 impl $type {
209 #[doc = "Unwrap '" $type "' into inner value."]
210 pub fn into_inner(self) -> $inner {
211 self.0
212 }
213 }
214 }
215 };
216 ( $type:ident < $a:ty > ) => {
217 $crate::paste::paste! {
218 impl < $a > $type < $a > {
219 #[doc = "Unwrap '" $type "' into inner value."]
220 pub fn into_inner(self) -> $a {
221 self.0
222 }
223 }
224 }
225 };
226}