Implement some more commands

This commit is contained in:
2024-11-30 17:12:49 +01:00
parent 1561ae2e80
commit 08104b3537
31 changed files with 926 additions and 10 deletions
+40
View File
@@ -0,0 +1,40 @@
use crate::{
commands::{
Command, Request, RequestParserError, RequestParserResult, ResponseAttributes,
ResponseParserError,
},
common::SongPosition,
};
pub struct Add;
impl Command for Add {
type Response = ();
const COMMAND: &'static str = "add";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let uri = match parts.next() {
Some(s) => s,
None => return Err(RequestParserError::UnexpectedEOF),
};
let position = match parts.next() {
Some(s) => Some(
s.parse::<SongPosition>()
.map_err(|_| RequestParserError::SyntaxError(1, s.to_owned()))?,
),
None => None,
};
debug_assert!(parts.next().is_none());
Ok((Request::Add(uri.to_string(), position), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
debug_assert!(parts.is_empty());
Ok(())
}
}
+55
View File
@@ -0,0 +1,55 @@
use crate::{
commands::{
Command, GenericResponseValue, Request, RequestParserError, RequestParserResult,
ResponseAttributes, ResponseParserError,
},
common::{SongId, SongPosition},
};
pub struct AddId;
pub struct AddIdResponse {
pub id: SongId,
}
impl Command for AddId {
type Response = AddIdResponse;
const COMMAND: &'static str = "addid";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let uri = match parts.next() {
Some(s) => s,
None => return Err(RequestParserError::UnexpectedEOF),
};
let position = match parts.next() {
Some(s) => Some(
s.parse::<SongPosition>()
.map_err(|_| RequestParserError::SyntaxError(1, s.to_owned()))?,
),
None => None,
};
debug_assert!(parts.next().is_none());
Ok((Request::AddId(uri.to_string(), position), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
let parts: Vec<_> = parts.into();
let (key, value) = parts.first().ok_or(ResponseParserError::UnexpectedEOF)?;
debug_assert!(key == &"Id");
let value = match value {
GenericResponseValue::Text(value) => value,
GenericResponseValue::Binary(_) => {
return Err(ResponseParserError::UnexpectedPropertyType("Id", "Binary"))
}
};
let id = value
.parse()
.map_err(|_| ResponseParserError::InvalidProperty("Id", value.to_owned()))?;
Ok(AddIdResponse { id })
}
}
+41
View File
@@ -0,0 +1,41 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct AddTagId;
impl Command for AddTagId {
type Response = ();
const COMMAND: &'static str = "addtagid";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let songid = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songid = songid
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, songid.to_string()))?;
let tag_name = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let tag_name = tag_name
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, tag_name.to_string()))?;
let tag_value = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let tag_value = tag_value
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, tag_value.to_string()))?;
debug_assert!(parts.next().is_none());
Ok((Request::AddTagId(songid, tag_name, tag_value), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
debug_assert!(parts.is_empty());
Ok(())
}
}
+22
View File
@@ -0,0 +1,22 @@
use crate::commands::{
Command, Request, RequestParserResult, ResponseAttributes, ResponseParserError,
};
pub struct Clear;
impl Command for Clear {
type Response = ();
const COMMAND: &'static str = "clear";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
debug_assert!(parts.next().is_none());
Ok((Request::Clear, ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
debug_assert!(parts.is_empty());
Ok(())
}
}
+36
View File
@@ -0,0 +1,36 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct ClearTagId;
impl Command for ClearTagId {
type Response = ();
const COMMAND: &'static str = "cleartagid";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let songid = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songid = songid
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, songid.to_string()))?;
let tag_name = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let tag_name = tag_name
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, tag_name.to_string()))?;
debug_assert!(parts.next().is_none());
Ok((Request::ClearTagId(songid, tag_name), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
debug_assert!(parts.is_empty());
Ok(())
}
}
+33
View File
@@ -0,0 +1,33 @@
use std::str::FromStr;
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
common::OneOrRange,
Request,
};
pub struct Delete;
impl Command for Delete {
type Response = ();
const COMMAND: &'static str = "delete";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let pos_or_range = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let one_or_range = OneOrRange::from_str(pos_or_range)
.map_err(|_| RequestParserError::SyntaxError(0, pos_or_range.to_string()))?;
debug_assert!(parts.next().is_none());
Ok((Request::Delete(one_or_range), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
debug_assert!(parts.is_empty());
Ok(())
}
}
+31
View File
@@ -0,0 +1,31 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct DeleteId;
impl Command for DeleteId {
type Response = ();
const COMMAND: &'static str = "deleteid";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let id = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let id = id
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, id.to_string()))?;
debug_assert!(parts.next().is_none());
Ok((Request::DeleteId(id), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
debug_assert!(parts.is_empty());
Ok(())
}
}
+36
View File
@@ -0,0 +1,36 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct Move;
impl Command for Move {
type Response = ();
const COMMAND: &'static str = "move";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let from_or_range = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let from_or_range = from_or_range
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, from_or_range.to_string()))?;
let to = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let to = to
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, to.to_string()))?;
debug_assert!(parts.next().is_none());
Ok((Request::Move(from_or_range, to), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
debug_assert!(parts.is_empty());
Ok(())
}
}
+36
View File
@@ -0,0 +1,36 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct MoveId;
impl Command for MoveId {
type Response = ();
const COMMAND: &'static str = "moveid";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let id = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let id = id
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, id.to_string()))?;
let to = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let to = to
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, to.to_string()))?;
debug_assert!(parts.next().is_none());
Ok((Request::MoveId(id, to), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
debug_assert!(parts.is_empty());
Ok(())
}
}
+22
View File
@@ -0,0 +1,22 @@
use crate::{
commands::{Command, RequestParserResult, ResponseAttributes, ResponseParserError},
Request,
};
pub struct Playlist;
impl Command for Playlist {
type Response = ();
const COMMAND: &'static str = "playlist";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
debug_assert!(parts.next().is_none());
Ok((Request::Playlist, ""))
}
fn parse_response(
_parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
unimplemented!()
}
}
+49
View File
@@ -0,0 +1,49 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct PlaylistFind;
impl Command for PlaylistFind {
type Response = ();
const COMMAND: &'static str = "playlistfind";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let filter = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let filter = filter.to_string();
let mut sort_or_window = parts.next();
let mut sort = None;
if let Some("sort") = sort_or_window {
sort = Some(
parts
.next()
.ok_or(RequestParserError::UnexpectedEOF)?
.to_string(),
);
sort_or_window = parts.next();
}
let mut window = None;
if let Some("window") = sort_or_window {
let w = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
window = Some(
w.parse()
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))?,
);
}
debug_assert!(parts.next().is_none());
Ok((Request::PlaylistFind(filter, sort, window), ""))
}
fn parse_response(
_parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
unimplemented!()
}
}
+30
View File
@@ -0,0 +1,30 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct PlaylistId;
impl Command for PlaylistId {
type Response = ();
const COMMAND: &'static str = "playlistid";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let id = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let id = id
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, id.to_string()))?;
debug_assert!(parts.next().is_none());
Ok((Request::PlaylistId(id), ""))
}
fn parse_response(
_parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
unimplemented!()
}
}
+33
View File
@@ -0,0 +1,33 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct PlaylistInfo;
impl Command for PlaylistInfo {
type Response = ();
const COMMAND: &'static str = "playlistinfo";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let one_or_range = parts
.next()
.map(|s| {
s.parse()
.map_err(|_| RequestParserError::SyntaxError(0, s.to_string()))
})
.transpose()?;
debug_assert!(parts.next().is_none());
Ok((Request::PlaylistInfo(one_or_range), ""))
}
fn parse_response(
_parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
unimplemented!()
}
}
+51
View File
@@ -0,0 +1,51 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct PlaylistSearch;
impl Command for PlaylistSearch {
type Response = ();
const COMMAND: &'static str = "playlistsearch";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let filter = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let filter = filter
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, filter.to_string()))?;
let mut sort_or_window = parts.next();
let mut sort = None;
if let Some("sort") = sort_or_window {
sort = Some(
parts
.next()
.ok_or(RequestParserError::UnexpectedEOF)?
.to_string(),
);
sort_or_window = parts.next();
}
let mut window = None;
if let Some("window") = sort_or_window {
let w = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
window = Some(
w.parse()
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))?,
);
}
debug_assert!(parts.next().is_none());
Ok((Request::PlaylistSearch(filter, sort, window), ""))
}
fn parse_response(
_parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
unimplemented!()
}
}
+38
View File
@@ -0,0 +1,38 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct PlChanges;
impl Command for PlChanges {
type Response = ();
const COMMAND: &'static str = "plchanges";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let version = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let version = version
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, version.to_string()))?;
let window = parts
.next()
.map(|w| {
w.parse()
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))
})
.transpose()?;
debug_assert!(parts.next().is_none());
Ok((Request::PlChanges(version, window), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
unimplemented!()
}
}
+38
View File
@@ -0,0 +1,38 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct PlChangesPosId;
impl Command for PlChangesPosId {
type Response = ();
const COMMAND: &'static str = "plchangesposid";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let version = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let version = version
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, version.to_string()))?;
let window = parts
.next()
.map(|w| {
w.parse()
.map_err(|_| RequestParserError::SyntaxError(0, w.to_string()))
})
.transpose()?;
debug_assert!(parts.next().is_none());
Ok((Request::PlChangesPosId(version, window), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
unimplemented!()
}
}
+36
View File
@@ -0,0 +1,36 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct Prio;
impl Command for Prio {
type Response = ();
const COMMAND: &'static str = "prio";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let prio = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let prio = prio
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, prio.to_string()))?;
let window = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let window = window
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, window.to_string()))?;
debug_assert!(parts.next().is_none());
Ok((Request::Prio(prio, window), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
debug_assert!(parts.is_empty());
Ok(())
}
}
+41
View File
@@ -0,0 +1,41 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct PrioId;
impl Command for PrioId {
type Response = ();
const COMMAND: &'static str = "prioid";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let prio = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let prio = prio
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, prio.to_string()))?;
let songids = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
// TODO: This is just a guess to satisfy compilation, double check it
let songids = songids
.split(',')
.map(|s| {
s.parse()
.map_err(|_| RequestParserError::SyntaxError(0, s.to_string()))
})
.collect::<Result<Vec<u32>, RequestParserError>>()?;
debug_assert!(parts.next().is_none());
Ok((Request::PrioId(prio, songids), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
debug_assert!(parts.is_empty());
Ok(())
}
}
+36
View File
@@ -0,0 +1,36 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct RangeId;
impl Command for RangeId {
type Response = ();
const COMMAND: &'static str = "rangeid";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let songid = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songid = songid
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, songid.to_string()))?;
let timeinterval = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let timeinterval = timeinterval
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, timeinterval.to_string()))?;
debug_assert!(parts.next().is_none());
Ok((Request::RangeId(songid, timeinterval), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
debug_assert!(parts.is_empty());
Ok(())
}
}
+35
View File
@@ -0,0 +1,35 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct Shuffle;
impl Command for Shuffle {
type Response = ();
const COMMAND: &'static str = "shuffle";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let range = parts
.next()
.map(|range| {
range
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, range.to_string()))
})
.transpose()?;
debug_assert!(parts.next().is_none());
Ok((Request::Shuffle(range), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
debug_assert!(parts.is_empty());
Ok(())
}
}
+36
View File
@@ -0,0 +1,36 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct Swap;
impl Command for Swap {
type Response = ();
const COMMAND: &'static str = "swap";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let songpos1 = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songpos1 = songpos1
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, songpos1.to_string()))?;
let songpos2 = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songpos2 = songpos2
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, songpos2.to_string()))?;
debug_assert!(parts.next().is_none());
Ok((Request::Swap(songpos1, songpos2), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
debug_assert!(parts.is_empty());
Ok(())
}
}
+36
View File
@@ -0,0 +1,36 @@
use crate::{
commands::{
Command, RequestParserError, RequestParserResult, ResponseAttributes, ResponseParserError,
},
Request,
};
pub struct SwapId;
impl Command for SwapId {
type Response = ();
const COMMAND: &'static str = "swapid";
fn parse_request(mut parts: std::str::SplitWhitespace<'_>) -> RequestParserResult<'_> {
let songid1 = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songid1 = songid1
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, songid1.to_string()))?;
let songid2 = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songid2 = songid2
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, songid2.to_string()))?;
debug_assert!(parts.next().is_none());
Ok((Request::SwapId(songid1, songid2), ""))
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError> {
debug_assert!(parts.is_empty());
Ok(())
}
}