diff --git a/src/bng/score.rs b/src/bng/score.rs index 84ba46c..4aadc1e 100644 --- a/src/bng/score.rs +++ b/src/bng/score.rs @@ -33,7 +33,7 @@ pub use de::*; use super::Expression as Instruction; -#[derive(Deref, From, Default)] +#[derive(Deref, From)] #[cfg_attr(debug_assertions, derive(Serialize, Debug))] pub struct Atoms(Vec); diff --git a/src/bng/score/de.rs b/src/bng/score/de.rs index aa97ecd..1745d76 100644 --- a/src/bng/score/de.rs +++ b/src/bng/score/de.rs @@ -2,7 +2,7 @@ use derive_new::new; use nom::{ character::complete::one_of, combinator::all_consuming, - multi::{many0, many1}, + multi::many0, sequence::{preceded, terminated}, Parser, }; @@ -60,12 +60,55 @@ impl<'de> Deserialize<'de> for Atoms { notes: String, sheet: String, } - let NotesSheet { notes, sheet } = NotesSheet::deserialize(deserializer)?; - if sheet.is_empty() { - Ok(Default::default()) - } else { - flat_atom_parser_mapper::(&sheet, flat_atom_parser(¬es)) + struct NotesSheetVisitor; + impl<'de> Visitor<'de> for NotesSheetVisitor { + type Value = NotesSheet; + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a \"notes\" field and a \"sheet\" field") + } + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + let notes = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(0, &self))?; + let sheet = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(1, &self))?; + Ok(NotesSheet::new(notes, sheet)) + } + fn visit_map(self, mut map: A) -> Result + where + A: de::MapAccess<'de>, + { + let mut notes = None; + let mut sheet = None; + while let Some(key) = map.next_key()? { + match key { + Field::Notes => { + if notes.is_some() { + return Err(de::Error::duplicate_field("notes")); + } + notes = Some(map.next_value()?); + } + Field::Sheet => { + if sheet.is_some() { + return Err(de::Error::duplicate_field("sheet")); + } + sheet = Some(map.next_value()?); + } + } + } + let notes = notes.ok_or_else(|| de::Error::missing_field("notes"))?; + let sheet = sheet.ok_or_else(|| de::Error::missing_field("sheet"))?; + Ok(NotesSheet::new(notes, sheet)) + } } + const FIELDS: &[&str] = &["notes", "sheet"]; + let NotesSheet { notes, sheet } = + deserializer.deserialize_struct("NotesSheet", FIELDS, NotesSheetVisitor)?; + flat_atom_parser_mapper::(&sheet, flat_atom_parser(¬es)) } } @@ -85,7 +128,7 @@ where P: Parser<&'a str, FlatAtom, nom::error::Error<&'a str>>, { all_consuming(terminated( - many1(preceded(maybe_yml_str_space(), parser)), + many0(preceded(maybe_yml_str_space(), parser)), maybe_yml_str_space(), ))(input) .map_err(nom_err_message)