helgoboss_midi/
newtype_macros.rs1#[derive(Clone, Eq, PartialEq, Debug, derive_more::Display)]
4#[display(fmt = "converting to type with smaller value range failed")]
5pub struct TryFromGreaterError(pub(crate) ());
6
7#[cfg(feature = "std")]
8impl std::error::Error for TryFromGreaterError {}
9
10#[derive(Clone, Eq, PartialEq, Debug, derive_more::Display)]
12#[display(fmt = "parsing string to MIDI type failed")]
13pub struct ParseIntError(pub(crate) ());
14
15#[cfg(feature = "std")]
16impl std::error::Error for ParseIntError {}
17
18macro_rules! newtype {
20 (
21 $(#[$outer:meta])*
22 name = $name: ident,
23 repr = $repr: ty,
24 max = $max: literal
25 ) => {
26 $(#[$outer])*
27 #[derive(
28 Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, derive_more::Display,
29 )]
30 #[cfg_attr(
31 feature = "serde",
32 derive(serde::Serialize, serde::Deserialize),
33 serde(try_from = "u16")
34 )]
35 pub struct $name(pub(crate) $repr);
36
37 impl $name {
38 pub const MIN: $name = $name(0);
40
41 pub const MAX: $name = $name($max);
43
44 fn is_valid<T: PartialOrd + From<$repr>>(number: T) -> bool {
45 number >= 0.into() && number <= $max.into()
46 }
47
48 doc_comment::doc_comment! {
49 concat!(
50"Creates a ", stringify!($name), ".
51
52# Panics
53
54This function panics if `value` is greater than ", $max, "."
55 ),
56 pub fn new(value: $repr) -> $name {
57 #[cfg(feature = "std")]
58 {
59 assert!($name::is_valid(value), concat!("{} is not a valid ", stringify!($name), " value"), value);
60 }
61 #[cfg(feature = "no_std")]
62 {
63 assert!($name::is_valid(value), concat!("not a valid ", stringify!($name), " value"));
64 }
65 $name(value)
66 }
67 }
68
69 doc_comment::doc_comment! {
70 concat!(
71"Creates a ", stringify!($name), " without checking `value`.
72
73# Safety
74
75`value` must not be greater than ", $max, "."
76 ),
77 pub const unsafe fn new_unchecked(value: $repr) -> $name {
78 $name(value)
79 }
80 }
81
82 pub const fn get(self) -> $repr {
84 self.0
85 }
86 }
87
88 impl core::str::FromStr for $name {
89 type Err = $crate::ParseIntError;
90
91 fn from_str(source: &str) -> Result<Self, Self::Err> {
92 let primitive = <$repr>::from_str(source).map_err(|_| $crate::ParseIntError(()))?;
93 if !$name::is_valid(primitive) {
94 return Err($crate::ParseIntError(()));
95 }
96 Ok($name(primitive))
97 }
98 }
99 };
100}
101
102macro_rules! impl_from_newtype_to_newtype {
105 ($from: ty, $into: ty) => {
106 impl From<$from> for $into {
107 fn from(value: $from) -> Self {
108 Self(value.0 as _)
109 }
110 }
111 };
112}
113
114macro_rules! impl_from_newtype_to_primitive {
117 ($from: ty, $into: ty) => {
118 impl From<$from> for $into {
119 fn from(value: $from) -> Self {
120 value.0 as _
121 }
122 }
123 };
124}
125
126macro_rules! impl_from_primitive_to_newtype {
128 ($from: ty, $into: ty) => {
129 impl From<$from> for $into {
130 fn from(value: $from) -> Self {
131 Self(value as _)
132 }
133 }
134 };
135}
136
137macro_rules! impl_try_from_newtype_to_newtype {
139 ($from: ty, $into: ty) => {
140 impl core::convert::TryFrom<$from> for $into {
141 type Error = $crate::TryFromGreaterError;
142
143 fn try_from(value: $from) -> Result<Self, Self::Error> {
144 if !Self::is_valid(value.0) {
145 return Err($crate::TryFromGreaterError(()));
146 }
147 Ok(Self(value.0 as _))
148 }
149 }
150 };
151}
152
153macro_rules! impl_try_from_primitive_to_newtype {
156 ($from: ty, $into: ty) => {
157 impl core::convert::TryFrom<$from> for $into {
158 type Error = $crate::TryFromGreaterError;
159
160 fn try_from(value: $from) -> Result<Self, Self::Error> {
161 if !Self::is_valid(value) {
162 return Err($crate::TryFromGreaterError(()));
163 }
164 Ok(Self(value as _))
165 }
166 }
167 };
168}