use super::{BeatType, Beats, TimeRelation};
use crate::datatypes::{TimeSeparator, TimeSymbol};
use alloc::{string::String, vec::Vec};
use musicxml_internal::*;
use musicxml_macros::*;
#[derive(Debug, Default, PartialEq, Eq, AttributeDeserialize, AttributeSerialize)]
pub struct InterchangeableAttributes {
pub separator: Option<TimeSeparator>,
pub symbol: Option<TimeSymbol>,
}
#[derive(Debug, PartialEq, Eq)]
pub struct InterchangeableBeatData {
pub beats: Beats,
pub beat_type: BeatType,
}
#[derive(Debug, Default, PartialEq, Eq)]
pub struct InterchangeableContents {
pub time_relation: Option<TimeRelation>,
pub beat_data: Vec<InterchangeableBeatData>,
}
impl ContentDeserializer for InterchangeableContents {
fn deserialize(elements: &[XmlElement]) -> Result<Self, String> {
let mut temp_beats: Option<Beats> = None;
let mut time_relation = None;
let mut beat_data = Vec::new();
for element in elements {
match element.name.as_str() {
"time-relation" => {
time_relation = Some(TimeRelation::deserialize(element)?);
}
"beats" => {
temp_beats = Some(Beats::deserialize(element)?);
}
"beat-type" => {
match &temp_beats {
Some(temp_beat) => beat_data.push(InterchangeableBeatData {
beats: temp_beat.clone(),
beat_type: BeatType::deserialize(element)?,
}),
_ => Err(String::from("Missing required \"beat\" element prior to \"beat-type\""))?,
};
temp_beats = None;
}
_ => (),
}
}
Ok(InterchangeableContents {
time_relation,
beat_data,
})
}
}
impl ContentSerializer for InterchangeableContents {
fn serialize(element: &Self) -> Vec<XmlElement> {
let mut elements: Vec<XmlElement> = Vec::new();
if let Some(el) = &element.time_relation {
elements.push(TimeRelation::serialize(el));
}
for el in &element.beat_data {
elements.push(Beats::serialize(&el.beats));
elements.push(BeatType::serialize(&el.beat_type));
}
elements
}
}
#[derive(Debug, PartialEq, Eq, ElementDeserialize, ElementSerialize)]
pub struct Interchangeable {
pub attributes: InterchangeableAttributes,
#[flatten]
pub content: InterchangeableContents,
}
#[cfg(test)]
mod interchangeable_tests {
use super::*;
use crate::datatypes::TimeSymbol;
use crate::elements::{BeatType, Beats};
use crate::parser::parse_from_xml_str;
#[test]
fn deserialize_valid1() {
let result = parse_from_xml_str::<Interchangeable>(
"<interchangeable symbol=\"dotted-note\">
<time-relation>parentheses</time-relation>
<beats>3</beats>
<beat-type>8</beat-type>
<beats>2</beats>
<beat-type>4</beat-type>
</interchangeable>",
);
assert!(result.is_ok());
assert_eq!(
result.unwrap(),
Interchangeable {
attributes: InterchangeableAttributes {
symbol: Some(TimeSymbol::DottedNote),
..Default::default()
},
content: InterchangeableContents {
time_relation: Some(TimeRelation {
attributes: (),
content: crate::datatypes::TimeRelation::Parentheses
}),
beat_data: vec![
InterchangeableBeatData {
beats: Beats {
attributes: (),
content: String::from("3")
},
beat_type: BeatType {
attributes: (),
content: String::from("8")
},
},
InterchangeableBeatData {
beats: Beats {
attributes: (),
content: String::from("2")
},
beat_type: BeatType {
attributes: (),
content: String::from("4")
},
},
],
},
}
);
}
}