From 612fa4db1167f645273decc82c11d55cf15ad18d Mon Sep 17 00:00:00 2001 From: h7x4 Date: Mon, 8 Dec 2025 05:31:13 +0900 Subject: [PATCH] make `ResponseParserError` self-contained, impl thiserror --- Cargo.toml | 1 + src/commands.rs | 67 ++++++++++--------- src/commands/audio_output_devices/outputs.rs | 12 ++-- src/commands/client_to_client/channels.rs | 4 +- src/commands/client_to_client/readmessages.rs | 4 +- src/commands/controlling_playback/play.rs | 4 +- src/commands/controlling_playback/playid.rs | 4 +- .../mounts_and_neighbors/listneighbors.rs | 2 +- src/commands/music_database/albumart.rs | 2 +- src/commands/music_database/count.rs | 2 +- src/commands/music_database/find.rs | 16 ++--- src/commands/music_database/getfingerprint.rs | 2 +- src/commands/music_database/list.rs | 2 +- src/commands/music_database/listall.rs | 2 +- src/commands/music_database/listallinfo.rs | 2 +- src/commands/music_database/listfiles.rs | 12 ++-- src/commands/music_database/lsinfo.rs | 2 +- src/commands/music_database/readcomments.rs | 6 +- src/commands/music_database/readpicture.rs | 2 +- src/commands/music_database/rescan.rs | 2 +- src/commands/music_database/search.rs | 16 ++--- src/commands/music_database/searchcount.rs | 2 +- src/commands/music_database/update.rs | 2 +- .../playback_options/replay_gain_status.rs | 7 +- .../querying_mpd_status/currentsong.rs | 2 +- src/commands/querying_mpd_status/stats.rs | 2 +- src/commands/querying_mpd_status/status.rs | 32 +++++---- src/commands/queue/addid.rs | 4 +- src/commands/queue/playlist.rs | 2 +- src/commands/queue/playlistfind.rs | 2 +- src/commands/queue/playlistid.rs | 2 +- src/commands/queue/playlistinfo.rs | 2 +- src/commands/queue/playlistsearch.rs | 2 +- src/commands/queue/plchanges.rs | 2 +- src/commands/queue/plchangesposid.rs | 2 +- src/commands/reflection/config.rs | 2 +- src/commands/reflection/decoders.rs | 8 +-- src/commands/stickers/sticker_find.rs | 10 +-- src/commands/stickers/sticker_list.rs | 21 ++++-- src/commands/stickers/stickernamestypes.rs | 10 ++- .../stored_playlists/listplaylistinfo.rs | 2 +- .../stored_playlists/listplaylists.rs | 2 +- .../stored_playlists/playlistlength.rs | 2 +- src/request.rs | 4 +- src/response_tokenizer.rs | 59 ++++++++-------- src/types/db_directory_info.rs | 10 +-- src/types/db_playlist_info.rs | 10 +-- src/types/db_selection_print.rs | 6 +- src/types/db_song_info.rs | 8 +-- 49 files changed, 212 insertions(+), 173 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6089f71..deebe67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ chrono = { version = "0.4.42", features = ["serde"] } lalrpop-util = { version = "0.22.2", features = ["lexer"] } paste = "1.0.15" serde = { version = "1.0.228", features = ["derive"] } +thiserror = "2.0.17" [dev-dependencies] indoc = "2.0.7" diff --git a/src/commands.rs b/src/commands.rs index 0e7eca7..72fd5f2 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -109,10 +109,10 @@ where /// Parses the response from its tokenized parts. /// See also [`parse_raw`]. - fn parse(parts: ResponseAttributes<'a>) -> Result>; + fn parse(parts: ResponseAttributes<'a>) -> Result; /// Parses the response from its raw byte representation. - fn parse_raw(raw: &'a [u8]) -> Result> { + fn parse_raw(raw: &'a [u8]) -> Result { Self::parse(ResponseAttributes::new_from_bytes(raw)) } } @@ -154,11 +154,11 @@ pub trait Command<'req, 'res> { /// Parse the response from its tokenized parts. See also [`parse_raw_response`]. fn parse_response( parts: ResponseAttributes<'res>, - ) -> Result> { + ) -> Result { Self::Response::parse(parts) } /// Parse the raw response string into a response. - fn parse_raw_response(raw: &'res [u8]) -> Result> { + fn parse_raw_response(raw: &'res [u8]) -> Result { Self::Response::parse_raw(raw) } } @@ -224,7 +224,7 @@ macro_rules! empty_command_response { fn parse( _parts: crate::commands::ResponseAttributes<'_>, - ) -> Result> { + ) -> Result { debug_assert!(_parts.is_empty()); Ok(paste::paste! { [<$name Response>] }) } @@ -319,8 +319,9 @@ macro_rules! single_optional_item_command_request { let item = parts .next() .map(|s| { - s.parse() - .map_err(|_| RequestParserError::SyntaxError(0, s.to_owned())) + s.parse().map_err(|_| { + crate::commands::RequestParserError::SyntaxError(0, s.to_owned()) + }) }) .transpose()?; @@ -350,13 +351,13 @@ macro_rules! single_item_command_response { fn parse( parts: crate::commands::ResponseAttributes<'_>, - ) -> Result> { + ) -> Result { let map = parts.into_map()?; debug_assert!(map.len() == 1, "Expected only one property in response"); let item_token = map.get($item_name).ok_or( - crate::commands::ResponseParserError::MissingProperty($item_name), + crate::commands::ResponseParserError::MissingProperty($item_name.to_string()), )?; let item_ = crate::response_tokenizer::expect_property_type!( Some(item_token), @@ -364,7 +365,10 @@ macro_rules! single_item_command_response { Text ); let item = item_.parse::<$item_type>().map_err(|_| { - crate::commands::ResponseParserError::InvalidProperty($item_name, item_) + crate::commands::ResponseParserError::InvalidProperty( + $item_name.to_string(), + item_.to_string(), + ) })?; Ok(paste::paste! { [<$name Response>] ( item ) }) @@ -391,12 +395,12 @@ macro_rules! multi_item_command_response { fn parse( parts: crate::commands::ResponseAttributes<'_>, - ) -> Result> { + ) -> Result { // TODO: use lazy vec let parts_: Vec<_> = parts.into_vec()?; if let Some((k, _)) = parts_.iter().find(|(k, _)| *k != $item_name) { - return Err(ResponseParserError::UnexpectedProperty(k)); + return Err(ResponseParserError::UnexpectedProperty(k.to_string())); } let mut items = Vec::with_capacity(parts_.len()); @@ -406,8 +410,8 @@ macro_rules! multi_item_command_response { let unwrapped_value = expect_property_type!(Some(value.1), $item_name, Text); let parsed_value = unwrapped_value.parse::<$item_type>().map_err(|_| { crate::commands::ResponseParserError::InvalidProperty( - $item_name, - unwrapped_value, + $item_name.to_string(), + unwrapped_value.to_string(), ) })?; @@ -426,6 +430,7 @@ pub(crate) use multi_item_command_response; pub(crate) use single_item_command_request; pub(crate) use single_item_command_response; pub(crate) use single_optional_item_command_request; +use thiserror::Error; #[derive(Debug, Clone, PartialEq)] pub enum RequestParserError { @@ -437,32 +442,34 @@ pub enum RequestParserError { MissingNewline, } -pub type ResponseParserResult<'a, T> = Result>; +pub type ResponseParserResult<'a, T> = Result; // TODO: should these be renamed to fit the mpd docs? // "Attribute" instead of "Property"? -#[derive(Debug, Clone, PartialEq)] -pub enum ResponseParserError<'a> { - /// A property was expected to be present in the response, but was not found. - MissingProperty(&'a str), +#[derive(Error, Debug, Clone, PartialEq)] +pub enum ResponseParserError { + #[error("A property was expected to be present in the response, but was not found: {0}")] + MissingProperty(String), // TODO: change name to UnexpectedPropertyEncoding - /// An expected property was found in the response, but its encoding was not as expected. (e.g. binary instead of text) - UnexpectedPropertyType(&'a str, &'a str), + #[error( + "An expected property was found in the response, but its encoding was not as expected: {0}: {1}" + )] + UnexpectedPropertyType(String, String), - /// A property was found in the response that was not expected. - UnexpectedProperty(&'a str), + #[error("A property was found in the response that was not expected: {0}")] + UnexpectedProperty(String), - /// A property was found multiple times in the response, but was only expected once. - DuplicateProperty(&'a str), + #[error("A property was found multiple times in the response, but was only expected once: {0}")] + DuplicateProperty(String), - /// The property value is parsable, but the value is invalid or nonsensical. - InvalidProperty(&'a str, &'a str), + #[error("The property value is parsable, but the value is invalid or nonsensical: {0}: {1}")] + InvalidProperty(String, String), - /// Could not parse the response due to a syntax error. - SyntaxError(u64, &'a str), + #[error("Could not parse the response due to a syntax error at position {0}: {1}")] + SyntaxError(u64, String), - /// Response ended early, while more properties were expected. + #[error("Response ended early, while more properties were expected")] UnexpectedEOF, // MissingNewline, } diff --git a/src/commands/audio_output_devices/outputs.rs b/src/commands/audio_output_devices/outputs.rs index 7be7398..2c9713d 100644 --- a/src/commands/audio_output_devices/outputs.rs +++ b/src/commands/audio_output_devices/outputs.rs @@ -33,7 +33,7 @@ impl CommandResponse<'_> for OutputsResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let mut outputs = Vec::new(); let mut id: Option = None; @@ -61,7 +61,7 @@ impl CommandResponse<'_> for OutputsResponse { let id_s = expect_property_type!(Some(v), k, Text); id = Some( id_s.parse() - .map_err(|_| ResponseParserError::SyntaxError(0, id_s))?, + .map_err(|_| ResponseParserError::SyntaxError(0, id_s.to_string()))?, ); } "outputname" => { @@ -74,7 +74,7 @@ impl CommandResponse<'_> for OutputsResponse { let val_s = expect_property_type!(Some(v), k, Text); let val: u64 = val_s .parse::() - .map_err(|_| ResponseParserError::SyntaxError(0, val_s))?; + .map_err(|_| ResponseParserError::SyntaxError(0, val_s.to_string()))?; enabled = Some(val != 0); } "attribute" => { @@ -82,16 +82,16 @@ impl CommandResponse<'_> for OutputsResponse { let mut parts = value.splitn(2, '='); let attr_key = parts .next() - .ok_or(ResponseParserError::SyntaxError(0, value))? + .ok_or(ResponseParserError::SyntaxError(0, value.to_string()))? .to_string(); let attr_value = parts .next() - .ok_or(ResponseParserError::SyntaxError(0, value))? + .ok_or(ResponseParserError::SyntaxError(0, value.to_string()))? .to_string(); attributes.insert(attr_key, attr_value); } _ => { - return Err(ResponseParserError::UnexpectedProperty(k)); + return Err(ResponseParserError::UnexpectedProperty(k.to_string())); } } } diff --git a/src/commands/client_to_client/channels.rs b/src/commands/client_to_client/channels.rs index 8224b37..d707e00 100644 --- a/src/commands/client_to_client/channels.rs +++ b/src/commands/client_to_client/channels.rs @@ -24,7 +24,7 @@ impl<'a> CommandResponse<'a> for ChannelsResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: Vec<_> = parts.into_vec()?; let mut channel_names = Vec::with_capacity(parts.len()); for (key, value) in parts { @@ -32,7 +32,7 @@ impl<'a> CommandResponse<'a> for ChannelsResponse { let channel_name = expect_property_type!(Some(value), "channels", Text); let channel_name = channel_name .parse() - .map_err(|_| ResponseParserError::SyntaxError(0, channel_name))?; + .map_err(|_| ResponseParserError::SyntaxError(0, channel_name.to_string()))?; channel_names.push(channel_name); } diff --git a/src/commands/client_to_client/readmessages.rs b/src/commands/client_to_client/readmessages.rs index f9725a3..7b4cf7f 100644 --- a/src/commands/client_to_client/readmessages.rs +++ b/src/commands/client_to_client/readmessages.rs @@ -28,7 +28,7 @@ impl CommandResponse<'_> for ReadMessagesResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: Vec<_> = parts.into_vec()?; debug_assert!(parts.len() % 2 == 0); @@ -44,7 +44,7 @@ impl CommandResponse<'_> for ReadMessagesResponse { let channel = expect_property_type!(Some(cvalue), "channel", Text); let channel = channel .parse() - .map_err(|_| ResponseParserError::SyntaxError(0, channel))?; + .map_err(|_| ResponseParserError::SyntaxError(0, channel.to_string()))?; let message = expect_property_type!(Some(mvalue), "message", Text).to_string(); diff --git a/src/commands/controlling_playback/play.rs b/src/commands/controlling_playback/play.rs index 0430963..51384a5 100644 --- a/src/commands/controlling_playback/play.rs +++ b/src/commands/controlling_playback/play.rs @@ -1,11 +1,11 @@ use crate::{ - commands::{Command, empty_command_response, single_item_command_request}, + commands::{Command, empty_command_response, single_optional_item_command_request}, types::SongPosition, }; pub struct Play; -single_item_command_request!(Play, "play", SongPosition); +single_optional_item_command_request!(Play, "play", SongPosition); empty_command_response!(Play); diff --git a/src/commands/controlling_playback/playid.rs b/src/commands/controlling_playback/playid.rs index fdc1930..98d3289 100644 --- a/src/commands/controlling_playback/playid.rs +++ b/src/commands/controlling_playback/playid.rs @@ -1,11 +1,11 @@ use crate::{ - commands::{Command, empty_command_response, single_item_command_request}, + commands::{Command, empty_command_response, single_optional_item_command_request}, types::SongId, }; pub struct PlayId; -single_item_command_request!(PlayId, "playid", SongId); +single_optional_item_command_request!(PlayId, "playid", SongId); empty_command_response!(PlayId); diff --git a/src/commands/mounts_and_neighbors/listneighbors.rs b/src/commands/mounts_and_neighbors/listneighbors.rs index e79ebbd..442c59f 100644 --- a/src/commands/mounts_and_neighbors/listneighbors.rs +++ b/src/commands/mounts_and_neighbors/listneighbors.rs @@ -23,7 +23,7 @@ impl CommandResponse<'_> for ListNeighborsResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: Vec<_> = parts.into_vec()?; debug_assert!(parts.len() % 2 == 0); diff --git a/src/commands/music_database/albumart.rs b/src/commands/music_database/albumart.rs index cad25ba..d986c86 100644 --- a/src/commands/music_database/albumart.rs +++ b/src/commands/music_database/albumart.rs @@ -72,7 +72,7 @@ impl CommandResponse<'_> for AlbumArtResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; let size = get_and_parse_property!(parts, "size", Text); diff --git a/src/commands/music_database/count.rs b/src/commands/music_database/count.rs index fe19f0d..a1e7bac 100644 --- a/src/commands/music_database/count.rs +++ b/src/commands/music_database/count.rs @@ -81,7 +81,7 @@ impl CommandResponse<'_> for CountResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; let songs = get_and_parse_property!(parts, "songs", Text); diff --git a/src/commands/music_database/find.rs b/src/commands/music_database/find.rs index aeb3139..c501ed7 100644 --- a/src/commands/music_database/find.rs +++ b/src/commands/music_database/find.rs @@ -96,19 +96,19 @@ impl CommandResponse<'_> for FindResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { DbSelectionPrintResponse::parse(parts)? .into_iter() .map(|i| match i { DbSelectionPrintResponse::Song(db_song_info) => Ok(db_song_info), - DbSelectionPrintResponse::Directory(_db_directory_info) => { - Err(ResponseParserError::UnexpectedProperty("directory")) - } - DbSelectionPrintResponse::Playlist(_db_playlist_info) => { - Err(ResponseParserError::UnexpectedProperty("playlist")) - } + DbSelectionPrintResponse::Directory(_db_directory_info) => Err( + ResponseParserError::UnexpectedProperty("directory".to_string()), + ), + DbSelectionPrintResponse::Playlist(_db_playlist_info) => Err( + ResponseParserError::UnexpectedProperty("playlist".to_string()), + ), }) - .collect::, ResponseParserError<'_>>>() + .collect::, ResponseParserError>>() .map(FindResponse) } } diff --git a/src/commands/music_database/getfingerprint.rs b/src/commands/music_database/getfingerprint.rs index 8905abc..0bab460 100644 --- a/src/commands/music_database/getfingerprint.rs +++ b/src/commands/music_database/getfingerprint.rs @@ -26,7 +26,7 @@ impl CommandResponse<'_> for GetFingerprintResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; let chromaprint = get_and_parse_property!(parts, "chromaprint", Text); diff --git a/src/commands/music_database/list.rs b/src/commands/music_database/list.rs index 8b82a46..0b29f4d 100644 --- a/src/commands/music_database/list.rs +++ b/src/commands/music_database/list.rs @@ -117,7 +117,7 @@ impl CommandResponse<'_> for ListResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts_: Vec<_> = parts.into_vec()?; debug_assert!({ let key = parts_.first().map(|(k, _)| k); diff --git a/src/commands/music_database/listall.rs b/src/commands/music_database/listall.rs index 9855855..45abea9 100644 --- a/src/commands/music_database/listall.rs +++ b/src/commands/music_database/listall.rs @@ -26,7 +26,7 @@ impl CommandResponse<'_> for ListAllResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let result = DbSelectionPrintResponse::parse(parts)?; Ok(ListAllResponse(result)) diff --git a/src/commands/music_database/listallinfo.rs b/src/commands/music_database/listallinfo.rs index cbe0f56..6c7747b 100644 --- a/src/commands/music_database/listallinfo.rs +++ b/src/commands/music_database/listallinfo.rs @@ -26,7 +26,7 @@ impl CommandResponse<'_> for ListAllInfoResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let result = DbSelectionPrintResponse::parse(parts)?; Ok(ListAllInfoResponse(result)) diff --git a/src/commands/music_database/listfiles.rs b/src/commands/music_database/listfiles.rs index df2e603..05b6a01 100644 --- a/src/commands/music_database/listfiles.rs +++ b/src/commands/music_database/listfiles.rs @@ -25,19 +25,19 @@ impl CommandResponse<'_> for ListFilesResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { DbSelectionPrintResponse::parse(parts)? .into_iter() .map(|i| match i { DbSelectionPrintResponse::Directory(db_directory_info) => Ok(db_directory_info), DbSelectionPrintResponse::Song(_db_song_info) => { - Err(ResponseParserError::UnexpectedProperty("file")) - } - DbSelectionPrintResponse::Playlist(_db_playlist_info) => { - Err(ResponseParserError::UnexpectedProperty("playlist")) + Err(ResponseParserError::UnexpectedProperty("file".to_string())) } + DbSelectionPrintResponse::Playlist(_db_playlist_info) => Err( + ResponseParserError::UnexpectedProperty("playlist".to_string()), + ), }) - .collect::, ResponseParserError<'_>>>() + .collect::, ResponseParserError>>() .map(ListFilesResponse) } } diff --git a/src/commands/music_database/lsinfo.rs b/src/commands/music_database/lsinfo.rs index dbb0639..ac9c803 100644 --- a/src/commands/music_database/lsinfo.rs +++ b/src/commands/music_database/lsinfo.rs @@ -25,7 +25,7 @@ impl CommandResponse<'_> for LsInfoResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let result = DbSelectionPrintResponse::parse(parts)?; Ok(LsInfoResponse(result)) diff --git a/src/commands/music_database/readcomments.rs b/src/commands/music_database/readcomments.rs index 0d88331..fe13f0c 100644 --- a/src/commands/music_database/readcomments.rs +++ b/src/commands/music_database/readcomments.rs @@ -24,14 +24,16 @@ impl CommandResponse<'_> for ReadCommentsResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; let comments = parts .iter() .map(|(k, v)| match v { GenericResponseValue::Text(s) => Ok((k.to_string(), s.to_string())), - GenericResponseValue::Binary(_) => Err(ResponseParserError::SyntaxError(1, k)), + GenericResponseValue::Binary(_) => { + Err(ResponseParserError::SyntaxError(1, k.to_string())) + } }) .collect::, ResponseParserError>>()?; diff --git a/src/commands/music_database/readpicture.rs b/src/commands/music_database/readpicture.rs index bad4a57..5ef92d9 100644 --- a/src/commands/music_database/readpicture.rs +++ b/src/commands/music_database/readpicture.rs @@ -75,7 +75,7 @@ impl CommandResponse<'_> for ReadPictureResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; // TODO: is empty response possible? diff --git a/src/commands/music_database/rescan.rs b/src/commands/music_database/rescan.rs index 59fa3f8..3b60e33 100644 --- a/src/commands/music_database/rescan.rs +++ b/src/commands/music_database/rescan.rs @@ -29,7 +29,7 @@ impl CommandResponse<'_> for RescanResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; let updating_db = get_and_parse_property!(parts, "updating_db", Text); diff --git a/src/commands/music_database/search.rs b/src/commands/music_database/search.rs index fb224d1..1645433 100644 --- a/src/commands/music_database/search.rs +++ b/src/commands/music_database/search.rs @@ -96,19 +96,19 @@ impl CommandResponse<'_> for SearchResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { DbSelectionPrintResponse::parse(parts)? .into_iter() .map(|i| match i { DbSelectionPrintResponse::Song(db_song_info) => Ok(db_song_info), - DbSelectionPrintResponse::Directory(_db_directory_info) => { - Err(ResponseParserError::UnexpectedProperty("directory")) - } - DbSelectionPrintResponse::Playlist(_db_playlist_info) => { - Err(ResponseParserError::UnexpectedProperty("playlist")) - } + DbSelectionPrintResponse::Directory(_db_directory_info) => Err( + ResponseParserError::UnexpectedProperty("directory".to_string()), + ), + DbSelectionPrintResponse::Playlist(_db_playlist_info) => Err( + ResponseParserError::UnexpectedProperty("playlist".to_string()), + ), }) - .collect::, ResponseParserError<'_>>>() + .collect::, ResponseParserError>>() .map(SearchResponse) } } diff --git a/src/commands/music_database/searchcount.rs b/src/commands/music_database/searchcount.rs index 970e454..d92f613 100644 --- a/src/commands/music_database/searchcount.rs +++ b/src/commands/music_database/searchcount.rs @@ -82,7 +82,7 @@ impl CommandResponse<'_> for SearchCountResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; let songs = get_and_parse_property!(parts, "songs", Text); diff --git a/src/commands/music_database/update.rs b/src/commands/music_database/update.rs index 6cc7aa3..f62e9a5 100644 --- a/src/commands/music_database/update.rs +++ b/src/commands/music_database/update.rs @@ -29,7 +29,7 @@ impl CommandResponse<'_> for UpdateResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; let updating_db = get_and_parse_property!(parts, "updating_db", Text); diff --git a/src/commands/playback_options/replay_gain_status.rs b/src/commands/playback_options/replay_gain_status.rs index 4a142d6..c5adbee 100644 --- a/src/commands/playback_options/replay_gain_status.rs +++ b/src/commands/playback_options/replay_gain_status.rs @@ -26,13 +26,16 @@ impl CommandResponse<'_> for ReplayGainStatusResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; let replay_gain_mode = get_property!(parts, "replay_gain_mode", Text); Ok(ReplayGainStatusResponse { replay_gain_mode: ReplayGainModeMode::from_str(replay_gain_mode).map_err(|_| { - ResponseParserError::InvalidProperty("replay_gain_mode", replay_gain_mode) + ResponseParserError::InvalidProperty( + "replay_gain_mode".to_string(), + replay_gain_mode.to_string(), + ) })?, }) } diff --git a/src/commands/querying_mpd_status/currentsong.rs b/src/commands/querying_mpd_status/currentsong.rs index 3fe469d..00e98d5 100644 --- a/src/commands/querying_mpd_status/currentsong.rs +++ b/src/commands/querying_mpd_status/currentsong.rs @@ -32,7 +32,7 @@ impl CommandResponse<'_> for CurrentSongResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let mut parts: HashMap<_, _> = parts.into_map()?; let position: SongPosition = get_and_parse_property!(parts, "Pos", Text); diff --git a/src/commands/querying_mpd_status/stats.rs b/src/commands/querying_mpd_status/stats.rs index c3f3f34..1dee3d7 100644 --- a/src/commands/querying_mpd_status/stats.rs +++ b/src/commands/querying_mpd_status/stats.rs @@ -33,7 +33,7 @@ impl CommandResponse<'_> for StatsResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; let uptime = get_and_parse_property!(parts, "uptime", Text); diff --git a/src/commands/querying_mpd_status/status.rs b/src/commands/querying_mpd_status/status.rs index 7d2bfac..f94333f 100644 --- a/src/commands/querying_mpd_status/status.rs +++ b/src/commands/querying_mpd_status/status.rs @@ -74,29 +74,33 @@ impl CommandResponse<'_> for StatusResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; let partition = get_property!(parts, "partition", Text).to_string(); let volume = match get_property!(parts, "volume", Text) { "-1" => None, - volume => Some( - volume - .parse() - .map_err(|_| ResponseParserError::InvalidProperty("volume", volume))?, - ), + volume => Some(volume.parse().map_err(|_| { + ResponseParserError::InvalidProperty("volume".to_string(), volume.to_string()) + })?), }; let repeat = match get_property!(parts, "repeat", Text) { "0" => Ok(false), "1" => Ok(true), - repeat => Err(ResponseParserError::InvalidProperty("repeat", repeat)), + repeat => Err(ResponseParserError::InvalidProperty( + "repeat".to_string(), + repeat.to_string(), + )), }?; let random = match get_property!(parts, "random", Text) { "0" => Ok(false), "1" => Ok(true), - random => Err(ResponseParserError::InvalidProperty("random", random)), + random => Err(ResponseParserError::InvalidProperty( + "random".to_string(), + random.to_string(), + )), }?; let single = get_and_parse_property!(parts, "single", Text); @@ -116,14 +120,18 @@ impl CommandResponse<'_> for StatusResponse { let mut parts = time.split(':'); let elapsed = parts .next() - .ok_or(ResponseParserError::SyntaxError(0, time))? + .ok_or(ResponseParserError::SyntaxError(0, time.to_string()))? .parse() - .map_err(|_| ResponseParserError::InvalidProperty("time", time))?; + .map_err(|_| { + ResponseParserError::InvalidProperty("time".to_string(), time.to_string()) + })?; let duration = parts .next() - .ok_or(ResponseParserError::SyntaxError(0, time))? + .ok_or(ResponseParserError::SyntaxError(0, time.to_string()))? .parse() - .map_err(|_| ResponseParserError::InvalidProperty("time", time))?; + .map_err(|_| { + ResponseParserError::InvalidProperty("time".to_string(), time.to_string()) + })?; Some((elapsed, duration)) } None => None, diff --git a/src/commands/queue/addid.rs b/src/commands/queue/addid.rs index 66de188..df2385e 100644 --- a/src/commands/queue/addid.rs +++ b/src/commands/queue/addid.rs @@ -73,12 +73,12 @@ impl CommandResponse<'_> for AddIdResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: Vec<_> = parts.into(); let mut iter = parts.into_iter(); let (key, id) = get_next_and_parse_property!(iter, Text); if key != "Id" { - return Err(ResponseParserError::UnexpectedProperty(key)); + return Err(ResponseParserError::UnexpectedProperty(key.to_string())); } Ok(AddIdResponse { id }) } diff --git a/src/commands/queue/playlist.rs b/src/commands/queue/playlist.rs index 56b5fae..f4d6036 100644 --- a/src/commands/queue/playlist.rs +++ b/src/commands/queue/playlist.rs @@ -22,7 +22,7 @@ impl CommandResponse<'_> for PlaylistResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { unimplemented!() } } diff --git a/src/commands/queue/playlistfind.rs b/src/commands/queue/playlistfind.rs index 9b01183..8000f77 100644 --- a/src/commands/queue/playlistfind.rs +++ b/src/commands/queue/playlistfind.rs @@ -105,7 +105,7 @@ impl CommandResponse<'_> for PlaylistFindResponse { todo!() } - fn parse(_parts: ResponseAttributes<'_>) -> Result> { + fn parse(_parts: ResponseAttributes<'_>) -> Result { unimplemented!() } } diff --git a/src/commands/queue/playlistid.rs b/src/commands/queue/playlistid.rs index 3453cd7..aedff98 100644 --- a/src/commands/queue/playlistid.rs +++ b/src/commands/queue/playlistid.rs @@ -30,7 +30,7 @@ impl CommandResponse<'_> for PlaylistIdResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { unimplemented!() } } diff --git a/src/commands/queue/playlistinfo.rs b/src/commands/queue/playlistinfo.rs index 7a40008..5ef699c 100644 --- a/src/commands/queue/playlistinfo.rs +++ b/src/commands/queue/playlistinfo.rs @@ -33,7 +33,7 @@ impl CommandResponse<'_> for PlaylistInfoResponse { todo!() } - fn parse(_parts: ResponseAttributes<'_>) -> Result> { + fn parse(_parts: ResponseAttributes<'_>) -> Result { unimplemented!() } } diff --git a/src/commands/queue/playlistsearch.rs b/src/commands/queue/playlistsearch.rs index b396017..78f92e1 100644 --- a/src/commands/queue/playlistsearch.rs +++ b/src/commands/queue/playlistsearch.rs @@ -104,7 +104,7 @@ impl CommandResponse<'_> for PlaylistSearchResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { unimplemented!() } } diff --git a/src/commands/queue/plchanges.rs b/src/commands/queue/plchanges.rs index f902a05..722d250 100644 --- a/src/commands/queue/plchanges.rs +++ b/src/commands/queue/plchanges.rs @@ -78,7 +78,7 @@ impl CommandResponse<'_> for PlChangesResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { unimplemented!() } } diff --git a/src/commands/queue/plchangesposid.rs b/src/commands/queue/plchangesposid.rs index 1aca07a..7e30471 100644 --- a/src/commands/queue/plchangesposid.rs +++ b/src/commands/queue/plchangesposid.rs @@ -77,7 +77,7 @@ impl CommandResponse<'_> for PlChangesPosIdResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { unimplemented!() } } diff --git a/src/commands/reflection/config.rs b/src/commands/reflection/config.rs index c86f400..1d8473e 100644 --- a/src/commands/reflection/config.rs +++ b/src/commands/reflection/config.rs @@ -27,7 +27,7 @@ impl CommandResponse<'_> for ConfigResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; let music_directory = get_property!(parts, "music_directory", Text).to_string(); diff --git a/src/commands/reflection/decoders.rs b/src/commands/reflection/decoders.rs index 38a80c2..f015837 100644 --- a/src/commands/reflection/decoders.rs +++ b/src/commands/reflection/decoders.rs @@ -28,7 +28,7 @@ impl CommandResponse<'_> for DecodersResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let mut result = Vec::new(); let mut current_decoder: Option = None; for (key, value) in parts.into_vec()?.into_iter() { @@ -49,19 +49,19 @@ impl CommandResponse<'_> for DecodersResponse { "suffix" => { current_decoder .as_mut() - .ok_or(ResponseParserError::SyntaxError(0, key))? + .ok_or(ResponseParserError::SyntaxError(0, key.to_string()))? .suffixes .push(expect_property_type!(Some(value), key, Text).to_string()); } "mime_type" => { current_decoder .as_mut() - .ok_or(ResponseParserError::SyntaxError(0, key))? + .ok_or(ResponseParserError::SyntaxError(0, key.to_string()))? .mime_types .push(expect_property_type!(Some(value), key, Text).to_string()); } k => { - return Err(ResponseParserError::UnexpectedProperty(k)); + return Err(ResponseParserError::UnexpectedProperty(k.to_string())); } } } diff --git a/src/commands/stickers/sticker_find.rs b/src/commands/stickers/sticker_find.rs index 2cd910b..0fe3872 100644 --- a/src/commands/stickers/sticker_find.rs +++ b/src/commands/stickers/sticker_find.rs @@ -130,7 +130,7 @@ impl CommandResponse<'_> for StickerFindResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: Vec<_> = parts.into_vec()?; let mut stickers = Vec::with_capacity(parts.len() / 2); @@ -144,7 +144,9 @@ impl CommandResponse<'_> for StickerFindResponse { .ok_or(ResponseParserError::UnexpectedEOF)?; if sticker.0 != "sticker" { - return Err(ResponseParserError::UnexpectedProperty(sticker.0)); + return Err(ResponseParserError::UnexpectedProperty( + sticker.0.to_string(), + )); } // TODO: check that this is a valid sticker type // debug_assert!(uri.0 == ""); @@ -157,11 +159,11 @@ impl CommandResponse<'_> for StickerFindResponse { let mut split = sticker.split("="); let name = split .next() - .ok_or(ResponseParserError::SyntaxError(0, sticker))? + .ok_or(ResponseParserError::SyntaxError(0, sticker.to_string()))? .to_string(); let value = split .next() - .ok_or(ResponseParserError::SyntaxError(1, sticker))? + .ok_or(ResponseParserError::SyntaxError(1, sticker.to_string()))? .to_string(); stickers.push(StickerFindResponseEntry { uri, name, value }); diff --git a/src/commands/stickers/sticker_list.rs b/src/commands/stickers/sticker_list.rs index 87e5918..030d859 100644 --- a/src/commands/stickers/sticker_list.rs +++ b/src/commands/stickers/sticker_list.rs @@ -66,19 +66,22 @@ impl CommandResponse<'_> for StickerListResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: Vec<_> = parts.into_vec()?; if let Some((k, _)) = parts.iter().find(|(k, _)| *k != "sticker") { - return Err(ResponseParserError::UnexpectedProperty(k)); + return Err(ResponseParserError::UnexpectedProperty(k.to_string())); } let result = parts .iter() .map(|(_, v)| match v { GenericResponseValue::Text(value) => Ok(value), - GenericResponseValue::Binary(_) => Err( - ResponseParserError::UnexpectedPropertyType("sticker", "Binary"), - ), + GenericResponseValue::Binary(_) => { + Err(ResponseParserError::UnexpectedPropertyType( + "sticker".to_string(), + "Binary".to_string(), + )) + } }) .collect::, ResponseParserError>>()?; @@ -88,8 +91,12 @@ impl CommandResponse<'_> for StickerListResponse { // TODO: This assumes the first = is the only one. // See: https://github.com/MusicPlayerDaemon/MPD/issues/2166 let mut split = v.split('='); - let key = split.next().ok_or(ResponseParserError::SyntaxError(0, v))?; - let value = split.next().ok_or(ResponseParserError::SyntaxError(1, v))?; + let key = split + .next() + .ok_or(ResponseParserError::SyntaxError(0, v.to_string()))?; + let value = split + .next() + .ok_or(ResponseParserError::SyntaxError(1, v.to_string()))?; Ok((key.to_string(), value.to_string())) }) .collect::, ResponseParserError>>() diff --git a/src/commands/stickers/stickernamestypes.rs b/src/commands/stickers/stickernamestypes.rs index fa40a65..102ea1b 100644 --- a/src/commands/stickers/stickernamestypes.rs +++ b/src/commands/stickers/stickernamestypes.rs @@ -66,7 +66,7 @@ impl CommandResponse<'_> for StickerNamesTypesResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: Vec<_> = parts.into_vec()?; let mut result = HashMap::new(); @@ -76,10 +76,14 @@ impl CommandResponse<'_> for StickerNamesTypesResponse { let (type_key, type_value) = name_type_pair[1]; if name_key != "name" { - return Err(ResponseParserError::UnexpectedProperty(name_key)); + return Err(ResponseParserError::UnexpectedProperty( + name_key.to_string(), + )); } if type_key != "type" { - return Err(ResponseParserError::UnexpectedProperty(type_key)); + return Err(ResponseParserError::UnexpectedProperty( + type_key.to_string(), + )); } let name = expect_property_type!(Some(name_value), "name", Text).to_string(); diff --git a/src/commands/stored_playlists/listplaylistinfo.rs b/src/commands/stored_playlists/listplaylistinfo.rs index 0f9a3da..de4fe30 100644 --- a/src/commands/stored_playlists/listplaylistinfo.rs +++ b/src/commands/stored_playlists/listplaylistinfo.rs @@ -70,7 +70,7 @@ impl CommandResponse<'_> for ListPlaylistInfoResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { unimplemented!() } } diff --git a/src/commands/stored_playlists/listplaylists.rs b/src/commands/stored_playlists/listplaylists.rs index f806d6b..3c25a89 100644 --- a/src/commands/stored_playlists/listplaylists.rs +++ b/src/commands/stored_playlists/listplaylists.rs @@ -29,7 +29,7 @@ impl CommandResponse<'_> for ListPlaylistsResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let mut parts = parts.into_lazy_vec().into_iter().peekable(); // TODO: count instances of 'playlist' to preallocate let mut result = Vec::new(); diff --git a/src/commands/stored_playlists/playlistlength.rs b/src/commands/stored_playlists/playlistlength.rs index e3cb99e..bcb5d4e 100644 --- a/src/commands/stored_playlists/playlistlength.rs +++ b/src/commands/stored_playlists/playlistlength.rs @@ -27,7 +27,7 @@ impl CommandResponse<'_> for PlaylistLengthResponse { todo!() } - fn parse(parts: ResponseAttributes<'_>) -> Result> { + fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; let songs = get_and_parse_property!(parts, "songs", Text); diff --git a/src/request.rs b/src/request.rs index 28f5014..dfbb6b3 100644 --- a/src/request.rs +++ b/src/request.rs @@ -36,8 +36,8 @@ pub enum Request { // -- Playback Control Commands -- // Next, Pause(Option), - Play(SongPosition), - PlayId(SongId), + Play(Option), + PlayId(Option), Previous, Seek(SongPosition, TimeWithFractions), SeekId(SongId, TimeWithFractions), diff --git a/src/response_tokenizer.rs b/src/response_tokenizer.rs index d9c7f15..549e92f 100644 --- a/src/response_tokenizer.rs +++ b/src/response_tokenizer.rs @@ -33,29 +33,27 @@ impl<'a> ResponseAttributes<'a> { pub fn into_map( self, - ) -> Result>, ResponseParserError<'a>> { + ) -> Result>, ResponseParserError> { self.into() } - pub fn into_vec( - self, - ) -> Result)>, ResponseParserError<'a>> { + pub fn into_vec(self) -> Result)>, ResponseParserError> { self.into() } pub fn into_lazy_vec( self, - ) -> Vec), ResponseParserError<'a>>> { + ) -> Vec), ResponseParserError>> { self.into() } - pub fn verify_all_keys_equal(&self, expected_key: &str) -> Result<(), ResponseParserError<'a>> { + pub fn verify_all_keys_equal(&self, expected_key: &str) -> Result<(), ResponseParserError> { let mut copy = self.clone(); copy.cursor = 0; for item in copy { let (key, _) = item?; if key != expected_key { - return Err(ResponseParserError::UnexpectedProperty(key)); + return Err(ResponseParserError::UnexpectedProperty(key.to_string())); } } Ok(()) @@ -67,7 +65,7 @@ impl<'a> ResponseAttributes<'a> { } impl<'a> Iterator for ResponseAttributes<'a> { - type Item = Result<(&'a str, GenericResponseValue<'a>), ResponseParserError<'a>>; + type Item = Result<(&'a str, GenericResponseValue<'a>), ResponseParserError>; fn next(&mut self) -> Option { if self.cursor >= self.bytestring.len() { @@ -121,7 +119,7 @@ impl<'a> Iterator for ResponseAttributes<'a> { // TODO: throw more specific error return Some(Err(ResponseParserError::SyntaxError( 0, - "Invalid byte count", + "Invalid byte count".to_string(), ))); } }; @@ -131,7 +129,7 @@ impl<'a> Iterator for ResponseAttributes<'a> { // TODO: throw more specific error return Some(Err(ResponseParserError::SyntaxError( 0, - "Invalid byte count", + "Invalid byte count".to_string(), ))); } }; @@ -170,14 +168,14 @@ impl<'a> Iterator for ResponseAttributes<'a> { } impl<'a> From> - for Result>, ResponseParserError<'a>> + for Result>, ResponseParserError> { fn from(val: ResponseAttributes<'a>) -> Self { let mut map = HashMap::new(); for item in val { let (k, v) = item?; if map.contains_key(k) { - return Err(ResponseParserError::DuplicateProperty(k)); + return Err(ResponseParserError::DuplicateProperty(k.to_string())); } map.insert(k, v); } @@ -186,7 +184,7 @@ impl<'a> From> } impl<'a> From> - for Vec), ResponseParserError<'a>>> + for Vec), ResponseParserError>> { fn from(val: ResponseAttributes<'a>) -> Self { val.collect() @@ -194,7 +192,7 @@ impl<'a> From> } impl<'a> From> - for Result)>, ResponseParserError<'a>> + for Result)>, ResponseParserError> { fn from(val: ResponseAttributes<'a>) -> Self { val.collect() @@ -220,8 +218,8 @@ macro_rules! _expect_property_type { }; return Err( crate::commands::ResponseParserError::UnexpectedPropertyType( - $name, - actual_type, + $name.to_string(), + actual_type.to_string(), ), ); } @@ -235,7 +233,10 @@ macro_rules! _parse_optional_property_type { $property .map(|value| { value.parse().map_err(|_| { - crate::commands::ResponseParserError::InvalidProperty($name, value) + crate::commands::ResponseParserError::InvalidProperty( + $name.to_string(), + value.to_string(), + ) }) }) .transpose()? @@ -246,7 +247,11 @@ macro_rules! _unwrap_optional_property_type { ($name:expr, $property:expr) => { match $property { Some(value) => value, - None => return Err(crate::commands::ResponseParserError::MissingProperty($name)), + None => { + return Err(crate::commands::ResponseParserError::MissingProperty( + $name.to_string(), + )) + } } }; } @@ -402,7 +407,7 @@ mod tests { #[test] #[cfg(debug_assertions)] - fn test_valid_hashmap_uniqueness_assert() -> Result<(), ResponseParserError<'static>> { + fn test_valid_hashmap_uniqueness_assert() -> Result<(), ResponseParserError> { let raw_response = indoc! { "a: 1 A: 2 @@ -431,7 +436,7 @@ mod tests { } #[test] - fn test_response_attributes_single_attribute() -> Result<(), ResponseParserError<'static>> { + fn test_response_attributes_single_attribute() -> Result<(), ResponseParserError> { let raw_response = indoc! { "name: Sticker1 OK" @@ -447,7 +452,7 @@ mod tests { } #[test] - fn test_response_attributes_multiple_attributes() -> Result<(), ResponseParserError<'static>> { + fn test_response_attributes_multiple_attributes() -> Result<(), ResponseParserError> { let raw_response = indoc! { "name: Sticker1 type: emoji @@ -467,7 +472,7 @@ mod tests { } #[test] - fn test_response_attributes_empty_response() -> Result<(), ResponseParserError<'static>> { + fn test_response_attributes_empty_response() -> Result<(), ResponseParserError> { let raw_response = indoc! { "OK" }; @@ -478,7 +483,7 @@ mod tests { } #[test] - fn test_response_attributes_unexpected_eof() -> Result<(), ResponseParserError<'static>> { + fn test_response_attributes_unexpected_eof() -> Result<(), ResponseParserError> { let raw_response = indoc! { "name: Sticker1 type: emoji" @@ -490,7 +495,7 @@ mod tests { } #[test] - fn test_response_attributes_repeated_attribute() -> Result<(), ResponseParserError<'static>> { + fn test_response_attributes_repeated_attribute() -> Result<(), ResponseParserError> { let raw_response = indoc! { "name: Sticker1 name: Sticker2 @@ -505,7 +510,7 @@ mod tests { } #[test] - fn test_response_attributes_empty_line() -> Result<(), ResponseParserError<'static>> { + fn test_response_attributes_empty_line() -> Result<(), ResponseParserError> { let raw_response = indoc! { "name: Sticker1 @@ -524,7 +529,7 @@ mod tests { } #[test] - fn test_response_attributes_no_value() -> Result<(), ResponseParserError<'static>> { + fn test_response_attributes_no_value() -> Result<(), ResponseParserError> { let raw_response = indoc! { "name: type: emoji @@ -539,7 +544,7 @@ mod tests { } #[test] - fn test_response_attributes_binary_data() -> Result<(), ResponseParserError<'static>> { + fn test_response_attributes_binary_data() -> Result<(), ResponseParserError> { let bytestring: &[u8] = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09"; let raw_response = { let mut response = format!("binary: {}\n", bytestring.len()).into_bytes(); diff --git a/src/types/db_directory_info.rs b/src/types/db_directory_info.rs index aefcbb8..5b29e09 100644 --- a/src/types/db_directory_info.rs +++ b/src/types/db_directory_info.rs @@ -21,18 +21,18 @@ impl DbDirectoryInfo { self.last_modified.is_some() } - pub fn parse(parts: ResponseAttributes<'_>) -> Result> { + pub fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; Self::parse_map(parts) } pub(crate) fn parse_map<'a>( parts: HashMap<&str, GenericResponseValue<'a>>, - ) -> Result> { + ) -> Result { let directory = get_property!(parts, "directory", Text); - let directory = directory - .parse() - .map_err(|_| ResponseParserError::InvalidProperty("directory", directory))?; + let directory = directory.parse().map_err(|_| { + ResponseParserError::InvalidProperty("directory".to_string(), directory.to_string()) + })?; let last_modified = get_optional_property!(parts, "Last-Modified", Text).map(|s| s.to_owned()); diff --git a/src/types/db_playlist_info.rs b/src/types/db_playlist_info.rs index 17a21e9..a181c9b 100644 --- a/src/types/db_playlist_info.rs +++ b/src/types/db_playlist_info.rs @@ -21,18 +21,18 @@ impl DbPlaylistInfo { self.last_modified.is_some() } - pub fn parse(parts: ResponseAttributes<'_>) -> Result> { + pub fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; Self::parse_map(parts) } pub(crate) fn parse_map<'a>( parts: HashMap<&str, GenericResponseValue<'a>>, - ) -> Result> { + ) -> Result { let playlist = get_property!(parts, "playlist", Text); - let playlist = playlist - .parse() - .map_err(|_| ResponseParserError::InvalidProperty("playlist", playlist))?; + let playlist = playlist.parse().map_err(|_| { + ResponseParserError::InvalidProperty("playlist".to_string(), playlist.to_string()) + })?; let last_modified = get_optional_property!(parts, "Last-Modified", Text).map(|s| s.to_owned()); diff --git a/src/types/db_selection_print.rs b/src/types/db_selection_print.rs index 7a7ce9d..25efd22 100644 --- a/src/types/db_selection_print.rs +++ b/src/types/db_selection_print.rs @@ -26,7 +26,7 @@ impl DbSelectionPrintResponse { pub fn parse( parts: ResponseAttributes<'_>, - ) -> Result, ResponseParserError<'_>> { + ) -> Result, ResponseParserError> { debug_assert!(!parts.is_empty()); let vec: Vec<_> = parts.into_vec()?; @@ -48,9 +48,9 @@ impl DbSelectionPrintResponse { "playlist" => { DbPlaylistInfo::parse_map(attrs).map(DbSelectionPrintResponse::Playlist) } - p => Err(ResponseParserError::UnexpectedProperty(p)), + p => Err(ResponseParserError::UnexpectedProperty(p.to_string())), }) - .collect::, ResponseParserError<'_>>>() + .collect::, ResponseParserError>>() } } diff --git a/src/types/db_song_info.rs b/src/types/db_song_info.rs index 8821f44..afcd29f 100644 --- a/src/types/db_song_info.rs +++ b/src/types/db_song_info.rs @@ -47,17 +47,17 @@ impl DbSongInfo { || self.playlist.is_some() } - pub fn parse(parts: ResponseAttributes<'_>) -> Result> { + pub fn parse(parts: ResponseAttributes<'_>) -> Result { let parts: HashMap<_, _> = parts.into_map()?; Self::parse_map(parts) } pub(crate) fn parse_map<'a>( mut parts: HashMap<&'a str, GenericResponseValue<'a>>, - ) -> Result> { + ) -> Result { let file: PathBuf = match remove_and_parse_next_optional_property!(parts, "file", Text) { Some(f) => f, - None => return Err(ResponseParserError::MissingProperty("file")), + None => return Err(ResponseParserError::MissingProperty("file".to_string())), }; if parts.is_empty() { @@ -88,7 +88,7 @@ impl DbSongInfo { let value = expect_property_type!(Some(value), key, Text).to_string(); Ok(Tag::new(key.to_string(), value)) }) - .collect::, ResponseParserError<'_>>>()?; + .collect::, ResponseParserError>>()?; tags.sort_unstable(); Ok(DbSongInfo {