rstmt_core/pitch/
pitch_class.rs

1/*
2    Appellation: pitch_class <module>
3    Created At: 2025.12.20:09:31:05
4    Contrib: @FL03
5*/
6use crate::pitch::{RawAccidental, RawPitchClass};
7
8/// The [`PitchClass`] implementations works to generically define the structure for a pitch
9/// class. This is accomplished through the use of two type parameters: `N`, which defines the
10/// note (e.g., C, D, E, etc.), and `K`, which defines the kind of pitch (e.g., sharp, flat,
11/// natural, etc.).
12///
13/// **Note**: This struct isn't designed to be used directly, rather through type aliases such
14/// as [`C`], [`DSharp`], [`EFlat`], etc.
15#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
16#[cfg_attr(
17    feature = "serde",
18    derive(serde::Deserialize, serde::Serialize),
19    serde(rename_all = "lowercase")
20)]
21#[repr(C)]
22pub struct PitchClass<P = super::CNote, K = <P as RawPitchClass>::Tag>
23where
24    P: RawPitchClass<Tag = K>,
25    K: RawAccidental,
26{
27    pub(crate) class: P,
28    pub(crate) kind: K,
29}
30
31/*
32 ************* Types *************
33*/
34macro_rules! classes {
35    (@impl $name:ident::<Natural>) => {
36        paste::paste! {
37            pub type $name = $crate::pitch::PitchClass<$crate::pitch::[<$name Note>], $crate::pitch::Natural>;
38        }
39    };
40    (@impl $name:ident::<$kind:ident>) => {
41        paste::paste! {
42            pub type [<$name $kind>] = $crate::pitch::PitchClass<$crate::pitch::[<$name $kind Note>], $crate::pitch::$kind>;
43        }
44    };
45    (@impl $name:ident::<$($kind:ident),+ $(,)?>) => {
46        $(classes! { @impl $name::<$kind> })*
47    };
48    ($($name:ident::<$($K:ident),* $(,)?>),* $(,)?) => {
49        $(classes! { @impl $name::<Natural, $($K),*> })*
50    };
51}
52
53classes! {
54    C::<Sharp>,
55    D::<Flat, Sharp>,
56    E::<Flat>,
57    F::<Sharp>,
58    G::<Flat, Sharp>,
59    A::<Flat, Sharp>,
60    B::<Flat>,
61}