use serde::de; use serde::de::value::MapDeserializer; use serde::forward_to_deserialize_any; use serde::Deserialize; use std::fmt; use std::time::Duration; mod error; use error::MpdResult; struct MPDeserializer<'de, Iter: Iterator> { inner: MapDeserializer<'de, Iter, error::Error>, } /// Deserialize time from an integer that represents the seconds. /// mpd uses int for the database stats (e.g. total time played). fn de_time_int<'de, D>(deserializer: D) -> Result where D: de::Deserializer<'de>, { u64::deserialize(deserializer).map(Duration::from_secs) } /// Deserialize time from a float that represents the seconds. /// mpd uses floats for the current status (e.g. time elapsed in song). fn de_time_float<'de, D>(deserializer: D) -> Result, D::Error> where D: de::Deserializer<'de>, { f64::deserialize(deserializer) .map(Duration::from_secs_f64) .map(Some) } /// mpd uses bints (0 or 1) to represent booleans, /// so we need a special parser for those. fn de_bint<'de, D>(deserializer: D) -> Result where D: de::Deserializer<'de>, { match u8::deserialize(deserializer)? { 0 => Ok(false), 1 => Ok(true), n => Err(de::Error::invalid_value( de::Unexpected::Unsigned(n as u64), &"zero or one", )), } } #[derive(Deserialize, Clone, Debug)] pub struct Track { pub file: String, pub artist_sort: Option, pub album_artist: Option, pub album_sort: Option, pub album_artist_sort: Option, #[serde(deserialize_with = "string_or_vec")] #[serde(default)] #[serde(rename = "performer")] pub performers: Vec, pub genre: Option, pub title: Option, pub track: Option, pub album: Option, pub artist: Option, pub pos: Option, pub id: Option, // TODO: use proper time here pub last_modified: Option, pub original_date: Option, pub time: Option, pub format: Option, #[serde(deserialize_with = "de_time_float")] pub duration: Option, pub label: Option, pub date: Option, pub disc: Option, pub musicbraiz_trackid: Option, pub musicbrainz_albumid: Option, pub musicbrainz_albumartistid: Option, pub musicbrainz_artistid: Option, pub musicbraiz_releasetrackid: Option, pub composer: Option, } // some unprintable character const SEPARATOR: char = '\x02'; impl<'de, Iter: Iterator> de::Deserializer<'de> for MPDeserializer<'de, Iter> { type Error = error::Error; fn deserialize_any(self, visitor: V) -> MpdResult where V: de::Visitor<'de>, { self.deserialize_map(visitor) } fn deserialize_map(self, visitor: V) -> MpdResult where V: de::Visitor<'de>, { visitor.visit_map(self.inner) } forward_to_deserialize_any! { bool char str string bytes byte_buf unit unit_struct seq tuple tuple_struct struct identifier ignored_any i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 option newtype_struct enum } } fn string_or_vec<'de, D>(deserializer: D) -> Result, D::Error> where D: de::Deserializer<'de>, { struct StringOrVec(); impl<'de> de::Visitor<'de> for StringOrVec { type Value = Vec; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("string or list of strings") } fn visit_str(self, value: &str) -> Result { Ok(value .split(SEPARATOR) .map(std::string::String::from) .collect()) } } deserializer.deserialize_any(StringOrVec()) } fn deserialize_response<'a, I: Iterator>(input: I) -> Result { let mut map: std::collections::HashMap = std::collections::HashMap::new(); for line in input { if let Some(_) = line.strip_prefix("OK") { break; } else if let Some(message) = line.strip_prefix("ACK") { return Err(error::Error { message: message.trim().to_string(), }); } let mut fields = line.splitn(2, ": "); match (fields.next(), fields.next()) { (Some(k), Some(v)) => { if let Some(existing) = map.get_mut(k) { existing.push(SEPARATOR); existing.push_str(v); } else { map.insert(k.to_string(), v.to_string()); } } _ => panic!("invalid response line: {:?}", line), } } return Ok(envy::from_iter(map).unwrap()); // let deser = MPDeserializer { // inner: MapDeserializer::new(map.into_iter()), // }; // Song::deserialize(deser) } fn main() { let input_str = "file: Youtube Rip/VVVVVV Medley.flac Last-Modified: 2018-03-07T13:18:01Z Album: VVVVVV OST / PPPPPP Artist: FamilyJules7x Composer: Magnus PĂ„lsson Date: 2014 Genre: Video Game Music Title: VVVVVV Medley Time: 433 duration: 432.727 Pos: 1548 Id: 1549"; let s = deserialize_response(input_str.lines()); dbg!(s); }