rstmt_core/pitch/traits/
accidental.rs1pub trait Accidental
10where
11 Self: 'static + AsRef<str> + Send + Sync + core::fmt::Debug + core::fmt::Display,
12{
13 private! {}
14
15 fn new() -> Self
16 where
17 Self: Sized;
18
19 #[allow(clippy::should_implement_trait)]
20 fn from_str(s: &str) -> Result<Self, crate::error::Error>
21 where
22 Self: Sized + core::str::FromStr<Err = crate::error::Error>,
23 {
24 s.parse::<Self>()
25 }
26
27 fn name(&self) -> &str;
28
29 fn symbol(&self) -> char;
30}
31
32macro_rules! accidental {
36 (@impl $(#[$meta:meta])* $vis:vis $type:ident $name:ident = $sym:literal $(;)?) => {
37 unit_type! {
38 $(#[$meta])*
39 #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
40 $vis $type $name
41 }
42
43 impl $name {
44 pub const NAME: &'static str = stringify!($name);
45 pub fn of<T>() -> bool
47 where
48 T: 'static,
49 {
50 ::core::any::TypeId::of::<T>() == ::core::any::TypeId::of::<Self>()
51 }
52 pub const fn symbol(&self) -> char {
54 $sym
55 }
56 pub fn name(&self) -> &str {
58 stringify!($name)
59 }
60 }
61
62 impl $crate::pitch::Accidental for $name {
63 seal! {}
64
65 fn new() -> Self {
66 Self
67 }
68
69 fn name(&self) -> &str {
70 self.name()
71 }
72
73 fn symbol(&self) -> char {
74 self.symbol()
75 }
76 }
77
78 impl AsRef<str> for $name {
79 fn as_ref(&self) -> &str {
80 stringify!($name)
81 }
82 }
83
84 impl ::core::fmt::Debug for $name {
85 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
86 write!(f, "{}", self.symbol())
87 }
88 }
89
90 impl ::core::fmt::Display for $name {
91 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
92 write!(f, "{}", self.symbol())
93 }
94 }
95 };
96 ($($vis:vis $type:ident $name:ident $(= $sym:literal)?);* $(;)?) => {
97 $(accidental! { @impl $vis $type $name $(= $sym)? })*
98 };
99}
100
101accidental! {
102 pub struct Flat = '♭';
103 pub struct Sharp = '♯';
104}
105
106#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
107#[cfg_attr(
108 feature = "serde",
109 derive(serde::Deserialize, serde::Serialize),
110 serde(rename_all = "snake_case")
111)]
112#[repr(transparent)]
113pub struct Natural;
114
115impl Natural {
116 pub const fn new() -> Self {
117 Self
118 }
119 pub fn of<T>() -> bool
121 where
122 T: 'static,
123 {
124 ::core::any::TypeId::of::<T>() == ::core::any::TypeId::of::<Self>()
125 }
126
127 pub const fn name(&self) -> &str {
128 "Natural"
129 }
130
131 pub const fn symbol(&self) -> char {
132 '♮'
133 }
134}
135
136impl Accidental for Natural {
137 seal! {}
138
139 fn new() -> Self {
140 Self::new()
141 }
142
143 fn name(&self) -> &str {
144 self.name()
145 }
146
147 fn symbol(&self) -> char {
148 self.symbol()
149 }
150}
151
152impl AsRef<str> for Natural {
153 fn as_ref(&self) -> &str {
154 "Natural"
155 }
156}
157
158impl AsRef<char> for Natural {
159 fn as_ref(&self) -> &char {
160 &'♮'
161 }
162}
163
164impl core::borrow::Borrow<str> for Natural {
165 fn borrow(&self) -> &str {
166 self.as_ref()
167 }
168}
169
170impl core::borrow::Borrow<char> for Natural {
171 fn borrow(&self) -> &char {
172 self.as_ref()
173 }
174}
175
176impl core::ops::Deref for Natural {
177 type Target = str;
178
179 fn deref(&self) -> &Self::Target {
180 self.as_ref()
181 }
182}
183
184impl core::str::FromStr for Natural {
185 type Err = crate::error::Error;
186
187 fn from_str(s: &str) -> Result<Self, Self::Err> {
188 if s.is_empty() || s.to_lowercase() == "natural" || s == "♮" {
189 Ok(Natural)
190 } else {
191 Err(anyhow::anyhow!("Unable to parse a natural note : {}", s).into())
192 }
193 }
194}
195
196impl core::fmt::Debug for Natural {
197 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
198 f.write_str(self.name())
199 }
200}
201
202impl core::fmt::Display for Natural {
203 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
204 write!(f, "{}", self.symbol())
205 }
206}
207
208#[cfg(feature = "alloc")]
209impl ::core::str::FromStr for Flat {
210 type Err = crate::error::Error;
211
212 fn from_str(s: &str) -> Result<Self, Self::Err> {
213 if s.to_lowercase() == "flat" || s == "♭" || s == "b" {
214 Ok(Self::default())
215 } else {
216 Err(anyhow::anyhow!("Invalid accidental string: {}", s).into())
217 }
218 }
219}
220
221#[cfg(feature = "alloc")]
222impl ::core::str::FromStr for Sharp {
223 type Err = crate::error::Error;
224
225 fn from_str(s: &str) -> Result<Self, Self::Err> {
226 if s.to_lowercase() == "sharp" || s == "♯" || s == "#" {
227 Ok(Self::default())
228 } else {
229 Err(anyhow::anyhow!("Invalid accidental string: {}", s).into())
230 }
231 }
232}