rstmt_core/pitch/
pitch.rs

1/*
2    Appellation: pitches <module>
3    Created At: 2025.12.20:10:02:21
4    Contrib: @FL03
5*/
6use rstmt_traits::Numerical;
7
8/// The [`Pitch`] implementation is a generic wrapper used to represent a musical pitch. A
9/// pitch is defined to be a perceptual property of sounds that enables one to define the
10/// _highness_ or _lowness_ of a sound. In music, pitch is often associated with the
11/// frequency of a sound wave, with higher frequencies corresponding to higher pitches.
12#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
13#[cfg_attr(
14    feature = "serde",
15    derive(serde::Deserialize, serde::Serialize),
16    serde(transparent)
17)]
18#[repr(transparent)]
19pub struct Pitch<T = f64>(pub T);
20
21/// [`RawPitch`] defines an interface for all raw pitch types.
22///
23/// **note:** This trait is sealed and cannot be implemented outside of this crate.
24pub trait RawPitch
25where
26    Self: Send + Sync + core::fmt::Debug + core::fmt::Display + PartialEq + PartialOrd,
27{
28    private! {}
29}
30/// [`NumPitch`] extends the `RawPitch` trait with additional capabilities for numerical types.
31/// The trait is automatically implemented for all
32pub trait NumPitch: RawPitch + Numerical {}
33
34/// A trait for converting a reference into a [`Pitch`].
35pub trait AsPitch<T>
36where
37    T: RawPitch,
38{
39    fn as_pitch(&self) -> Pitch<T>;
40}
41/// [`IntoPitch`] defines a consuming conversion from some type into a [`Pitch`].
42pub trait IntoPitch<T>
43where
44    T: RawPitch,
45{
46    fn into_pitch(self) -> Pitch<T>;
47
48    private! {}
49}
50/// The [`Pitched`] trait provides a method for viewing the pitch of the implementor.
51pub trait Pitched<T>
52where
53    T: RawPitch,
54{
55    fn pitch(&self) -> Pitch<&T>;
56}
57
58/*
59 ************* Implementations *************
60*/
61impl<U, T> AsPitch<T> for U
62where
63    U: Clone + IntoPitch<T>,
64    T: RawPitch,
65{
66    fn as_pitch(&self) -> Pitch<T> {
67        self.clone().into_pitch()
68    }
69}
70
71impl<U, T> IntoPitch<T> for U
72where
73    U: Into<Pitch<T>>,
74    T: RawPitch,
75{
76    fn into_pitch(self) -> Pitch<T> {
77        self.into()
78    }
79
80    seal! {}
81}
82
83impl<T> RawPitch for &T
84where
85    T: RawPitch,
86{
87    seal! {}
88}
89
90impl<T> RawPitch for &mut T
91where
92    T: RawPitch,
93{
94    seal! {}
95}
96
97impl<T> NumPitch for T where T: RawPitch + Numerical {}
98
99macro_rules! impl_raw_pitch {
100    ($($tgt:ty),* $(,)?) => {
101        $(
102            impl RawPitch for $tgt {
103                seal! {}
104            }
105        )*
106    };
107}
108
109impl_raw_pitch! {
110    u8, u16, u32, u64, u128, usize,
111    i8, i16, i32, i64, i128, isize,
112    f32, f64
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn test_pitch_creation() {
121        let a4 = Pitch(440f64);
122        assert_eq! { a4, 440.0 }
123    }
124}