1mod impl_aspn;
6mod impl_aspn_ext;
7mod impl_note_base;
8mod impl_note_ext;
9mod impl_note_repr;
10
11use crate::octave::Octave;
12use crate::pitch::{self, PitchClass, RawAccidental, RawPitchClass};
13
14pub trait AsAspn {
16 fn as_aspn(&self) -> Aspn;
17}
18pub trait IntoAspn {
20 fn into_aspn(self) -> Aspn;
21}
22
23#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
30#[cfg_attr(
31 feature = "serde",
32 derive(serde::Deserialize, serde::Serialize),
33 serde(deny_unknown_fields, default, rename_all = "snake_case")
34)]
35#[repr(C)]
36pub struct Aspn {
37 pub(crate) class: usize,
38 pub(crate) octave: Octave,
39}
40
41#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
43#[cfg_attr(
44 feature = "serde",
45 derive(serde::Deserialize, serde::Serialize),
46 serde(rename_all = "snake_case")
47)]
48#[repr(C)]
49pub struct NoteBase<P = pitch::CNote, K = <P as RawPitchClass>::Tag>
50where
51 P: RawPitchClass<Tag = K>,
52 K: RawAccidental,
53{
54 pub(crate) class: PitchClass<P, K>,
55 pub(crate) octave: Octave,
56}
57
58impl<T> AsAspn for T
62where
63 T: Clone + IntoAspn,
64{
65 fn as_aspn(&self) -> Aspn {
66 self.clone().into_aspn()
67 }
68}
69
70impl<T> IntoAspn for T
71where
72 T: Into<Aspn>,
73{
74 fn into_aspn(self) -> Aspn {
75 self.into()
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::NoteBase;
82 use crate::octave::Octave;
83 use crate::pitch::{C, CNote};
84
85 #[test]
86 fn test_note_from_octave() {
87 assert_eq! { NoteBase::<CNote>::from_octave(Octave(4)), "C.4" }
88 }
89 #[test]
90 fn test_note_parse() {
92 let exp = NoteBase::new(C::default(), Octave(4));
93 assert_eq! { "C.4".parse::<NoteBase<_, _>>().unwrap(), exp }
94 }
95}