use serde::de; use std::collections::HashMap; mod error; use error::{Error, MpdResult}; mod structs; pub use structs::{Position, Track}; /// some unprintable character to separate repeated keys const SEPARATOR: char = '\x02'; pub fn deserialize_response<'a, I: Iterator, T: de::DeserializeOwned>(input: I) -> MpdResult { let mut map: HashMap = HashMap::new(); for line in input { if line.starts_with("OK") { break; } else if let Some(message) = line.strip_prefix("ACK") { return Err(Error::from_str(message.trim())); } 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), } } // Eventually, I’d like to use my own deserializer instead of envy Ok(envy::from_iter(map).unwrap()) } #[cfg(test)] mod tests { use super::*; use chrono::DateTime; #[test] fn track_de_test() { let input_str = "file: American Pie.flac Last-Modified: 2019-12-16T21:38:54Z Album: American Pie Artist: Don McLean Date: 1979 Genre: Rock Title: American Pie Track: 1 Time: 512 duration: 512.380 Pos: 1367 Id: 1368 OK"; let t: Track = deserialize_response(input_str.lines()).unwrap(); assert_eq!( t, Track { file: "American Pie.flac".to_string(), last_modified: Some(DateTime::parse_from_rfc3339("2019-12-16T21:38:54Z").unwrap()), album: Some("American Pie".to_string()), artist: Some("Don McLean".to_string()), date: Some(1979), genre: Some("Rock".to_string()), title: Some("American Pie".to_string()), track: Some(Position { item_position: 1, total_items: None, }), duration: std::time::Duration::from_secs_f64(512.380), pos: 1367, id: 1368, ..Track::default() } ); } #[test] fn repeated_field_test() { let input_str = r#"file: 06 Symphonie No. 41 en ut majeur, K. 551 _Jupiter_ I. Allegro Vivace.flac Last-Modified: 2018-11-11T09:01:54Z Album: Symphonies n°40 & n°41 AlbumArtist: Wolfgang Amadeus Mozart; Royal Philharmonic Orchestra, Jane Glover AlbumArtistSort: Mozart, Wolfgang Amadeus; Royal Philharmonic Orchestra, Glover, Jane Artist: Wolfgang Amadeus Mozart ArtistSort: Mozart, Wolfgang Amadeus Composer: Wolfgang Amadeus Mozart Date: 2005 Disc: 1 Disc: 1 MUSICBRAINZ_ALBUMARTISTID: b972f589-fb0e-474e-b64a-803b0364fa75 MUSICBRAINZ_ALBUMID: 688d9252-f897-4ab6-879d-5cb83bb71087 MUSICBRAINZ_ARTISTID: b972f589-fb0e-474e-b64a-803b0364fa75 MUSICBRAINZ_RELEASETRACKID: 54a2632f-fa98-3713-bd75-d7effc03d0b1 MUSICBRAINZ_TRACKID: 2dd10dd8-e8de-4479-a092-9a04c2760fd6 OriginalDate: 1993 Title: Symphonie No. 41 en ut majeur, K. 551 "Jupiter": I. Allegro Vivace Track: 6 Track: 6 Time: 683 Performer: Royal Philharmonic Orchestra duration: 682.840 Performer: Jane Glover Pos: 3439 Id: 3440 OK"#; let t: Track = deserialize_response(input_str.lines()).unwrap(); assert_eq!( t, Track { file: "06 Symphonie No. 41 en ut majeur, K. 551 _Jupiter_ I. Allegro Vivace.flac".to_string(), last_modified: Some(DateTime::parse_from_rfc3339("2018-11-11T09:01:54Z").unwrap()), album: Some("Symphonies n°40 & n°41".to_string()), artist: Some("Wolfgang Amadeus Mozart".to_string()), artist_sort: Some("Mozart, Wolfgang Amadeus".to_string()), album_artist: Some("Wolfgang Amadeus Mozart; Royal Philharmonic Orchestra, Jane Glover".to_string()), album_artist_sort: Some("Mozart, Wolfgang Amadeus; Royal Philharmonic Orchestra, Glover, Jane".to_string()), composer: Some("Wolfgang Amadeus Mozart".to_string()), date: Some(2005), original_date: Some(1993), title: Some("Symphonie No. 41 en ut majeur, K. 551 \"Jupiter\": I. Allegro Vivace".to_string()), disc: Some(Position { item_position: 1, total_items: Some(1), }), track: Some(Position { item_position: 6, total_items: Some(6), }), duration: std::time::Duration::from_secs_f64(682.840), pos: 3439, id: 3440, performers: vec!["Royal Philharmonic Orchestra".to_string(), "Jane Glover".to_string()], musicbrainz_albumartistid: Some("b972f589-fb0e-474e-b64a-803b0364fa75".to_string()), musicbrainz_albumid: Some("688d9252-f897-4ab6-879d-5cb83bb71087".to_string()), musicbrainz_artistid: Some("b972f589-fb0e-474e-b64a-803b0364fa75".to_string()), musicbrainz_releasetrackid: Some("54a2632f-fa98-3713-bd75-d7effc03d0b1".to_string()), musicbrainz_trackid: Some("2dd10dd8-e8de-4479-a092-9a04c2760fd6".to_string()), ..Track::default() } ); } }