commands: split Command trait into req + res parts

This commit is contained in:
2025-12-05 22:54:01 +09:00
parent c43fa3cfdb
commit ffb1911b89
147 changed files with 3748 additions and 3578 deletions
+25 -23
View File
@@ -1,10 +1,9 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, CommandRequest, RequestParserError, empty_command_response},
common::types::{SongPosition, Uri},
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
};
pub struct Add;
@@ -15,25 +14,28 @@ pub struct AddRequest {
position: Option<SongPosition>,
}
impl AddRequest {
pub fn new(uri: Uri, position: Option<SongPosition>) -> Self {
Self { uri, position }
}
}
impl Command for Add {
type Request = AddRequest;
type Response = ();
impl CommandRequest<'_> for AddRequest {
const COMMAND: &'static str = "add";
fn serialize_request(&self, request: Self::Request) -> String {
match request.position {
Some(position) => format!("{} {} {}", Self::COMMAND, request.uri, position),
None => format!("{} {}", Self::COMMAND, request.uri),
fn into_request_enum(self) -> crate::Request {
crate::Request::Add(self.uri, self.position)
}
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::Add(uri, position) => Some(AddRequest { uri, position }),
_ => None,
}
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn serialize(&self) -> String {
match self.position {
Some(position) => format!("{} {} {}", Self::COMMAND, self.uri, position),
None => format!("{} {}", Self::COMMAND, self.uri),
}
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let uri = match parts.next() {
Some(s) => s,
None => return Err(RequestParserError::UnexpectedEOF),
@@ -54,11 +56,11 @@ impl Command for Add {
position,
})
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
debug_assert!(parts.is_empty());
Ok(())
}
}
empty_command_response!(Add);
impl Command<'_, '_> for Add {
type Request = AddRequest;
type Response = AddResponse;
}
+39 -17
View File
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError},
common::types::{SongId, SongPosition, Uri},
request_tokenizer::RequestTokenizer,
response_tokenizer::{ResponseAttributes, get_next_and_parse_property},
@@ -15,24 +15,28 @@ pub struct AddIdRequest {
pub position: Option<SongPosition>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AddIdResponse {
pub id: SongId,
}
impl Command for AddId {
type Request = AddIdRequest;
type Response = AddIdResponse;
impl CommandRequest<'_> for AddIdRequest {
const COMMAND: &'static str = "addid";
fn serialize_request(&self, request: Self::Request) -> String {
match request.position {
Some(pos) => format!("{} {} {}", Self::COMMAND, request.uri, pos),
None => format!("{} {}", Self::COMMAND, request.uri),
fn into_request_enum(self) -> crate::Request {
crate::Request::AddId(self.uri, self.position)
}
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::AddId(uri, position) => Some(AddIdRequest { uri, position }),
_ => None,
}
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn serialize(&self) -> String {
match self.position {
Some(pos) => format!("{} {} {}", Self::COMMAND, self.uri, pos),
None => format!("{} {}", Self::COMMAND, self.uri),
}
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let uri = match parts.next() {
Some(s) => s,
None => return Err(RequestParserError::UnexpectedEOF),
@@ -53,10 +57,23 @@ impl Command for AddId {
position,
})
}
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AddIdResponse {
pub id: SongId,
}
impl CommandResponse<'_> for AddIdResponse {
fn into_response_enum(self) -> crate::Response {
todo!()
}
fn from_response_enum(response: crate::Response) -> Option<Self> {
todo!()
}
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError<'_>> {
let parts: Vec<_> = parts.into();
let mut iter = parts.into_iter();
let (key, id) = get_next_and_parse_property!(iter, Text);
@@ -66,3 +83,8 @@ impl Command for AddId {
Ok(AddIdResponse { id })
}
}
impl Command<'_, '_> for AddId {
type Request = AddIdRequest;
type Response = AddIdResponse;
}
+29 -16
View File
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseAttributes, ResponseParserError},
commands::{Command, CommandRequest, RequestParserError, empty_command_response},
common::types::{SongId, TagName, TagValue},
request_tokenizer::RequestTokenizer,
};
@@ -15,22 +15,35 @@ pub struct AddTagIdRequest {
pub tag_value: TagValue,
}
impl Command for AddTagId {
type Request = AddTagIdRequest;
type Response = ();
impl CommandRequest<'_> for AddTagIdRequest {
const COMMAND: &'static str = "addtagid";
fn serialize_request(&self, request: Self::Request) -> String {
fn into_request_enum(self) -> crate::Request {
crate::Request::AddTagId(self.songid, self.tag_name, self.tag_value)
}
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::AddTagId(songid, tag_name, tag_value) => Some(AddTagIdRequest {
songid,
tag_name,
tag_value,
}),
_ => None,
}
}
fn serialize(&self) -> String {
format!(
"{} {} {} {}",
Self::COMMAND,
request.songid,
request.tag_name,
request.tag_value
self.songid,
self.tag_name,
self.tag_value
)
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let songid = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songid = songid
.parse()
@@ -54,11 +67,11 @@ impl Command for AddTagId {
tag_value,
})
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
debug_assert!(parts.is_empty());
Ok(())
}
}
empty_command_response!(AddTagId);
impl Command<'_, '_> for AddTagId {
type Request = AddTagIdRequest;
type Response = AddTagIdResponse;
}
+6 -23
View File
@@ -1,29 +1,12 @@
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
};
use crate::commands::{Command, empty_command_request, empty_command_response};
pub struct Clear;
impl Command for Clear {
type Request = ();
type Response = ();
const COMMAND: &'static str = "clear";
empty_command_request!(Clear, "clear");
fn serialize_request(&self, _request: Self::Request) -> String {
Self::COMMAND.to_string()
}
empty_command_response!(Clear);
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
debug_assert!(parts.next().is_none());
Ok(())
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
debug_assert!(parts.is_empty());
Ok(())
}
impl Command<'_, '_> for Clear {
type Request = ClearRequest;
type Response = ClearResponse;
}
+25 -15
View File
@@ -1,10 +1,9 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, CommandRequest, RequestParserError, empty_command_response},
common::types::{SongId, TagName},
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
};
pub struct ClearTagId;
@@ -15,16 +14,27 @@ pub struct ClearTagIdRequest {
pub tag_name: TagName,
}
impl Command for ClearTagId {
type Request = ClearTagIdRequest;
type Response = ();
impl CommandRequest<'_> for ClearTagIdRequest {
const COMMAND: &'static str = "cleartagid";
fn serialize_request(&self, request: Self::Request) -> String {
format!("{} {} {}", Self::COMMAND, request.songid, request.tag_name)
fn into_request_enum(self) -> crate::Request {
crate::Request::ClearTagId(self.songid, self.tag_name)
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::ClearTagId(songid, tag_name) => {
Some(ClearTagIdRequest { songid, tag_name })
}
_ => None,
}
}
fn serialize(&self) -> String {
format!("{} {} {}", Self::COMMAND, self.songid, self.tag_name)
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let songid = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songid = songid
.parse()
@@ -39,11 +49,11 @@ impl Command for ClearTagId {
Ok(ClearTagIdRequest { songid, tag_name })
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
debug_assert!(parts.is_empty());
Ok(())
}
}
empty_command_response!(ClearTagId);
impl Command<'_, '_> for ClearTagId {
type Request = ClearTagIdRequest;
type Response = ClearTagIdResponse;
}
+6 -28
View File
@@ -1,37 +1,15 @@
use std::str::FromStr;
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, empty_command_response, single_item_command_request},
common::types::OneOrRange,
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
};
pub struct Delete;
impl Command for Delete {
type Request = OneOrRange;
type Response = ();
const COMMAND: &'static str = "delete";
single_item_command_request!(Delete, "delete", OneOrRange);
fn serialize_request(&self, request: Self::Request) -> String {
format!("{} {}", Self::COMMAND, request)
}
empty_command_response!(Delete);
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
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(one_or_range)
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
debug_assert!(parts.is_empty());
Ok(())
}
impl Command<'_, '_> for Delete {
type Request = DeleteRequest;
type Response = DeleteResponse;
}
+6 -27
View File
@@ -1,36 +1,15 @@
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, empty_command_response, single_item_command_request},
common::types::SongId,
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
};
pub struct DeleteId;
impl Command for DeleteId {
type Request = SongId;
type Response = ();
const COMMAND: &'static str = "deleteid";
single_item_command_request!(DeleteId, "deleteid", SongId);
fn serialize_request(&self, request: Self::Request) -> String {
format!("{} {}", Self::COMMAND, request)
}
empty_command_response!(DeleteId);
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
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(id)
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
debug_assert!(parts.is_empty());
Ok(())
}
impl Command<'_, '_> for DeleteId {
type Request = DeleteIdRequest;
type Response = DeleteIdResponse;
}
+23 -14
View File
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseAttributes, ResponseParserError},
commands::{Command, CommandRequest, RequestParserError, empty_command_response},
common::types::{AbsouluteRelativeSongPosition, OneOrRange},
request_tokenizer::RequestTokenizer,
};
@@ -14,16 +14,25 @@ pub struct MoveRequest {
pub to: AbsouluteRelativeSongPosition,
}
impl Command for Move {
type Request = MoveRequest;
type Response = ();
impl CommandRequest<'_> for MoveRequest {
const COMMAND: &'static str = "move";
fn serialize_request(&self, request: Self::Request) -> String {
format!("{} {} {}", Self::COMMAND, request.from_or_range, request.to)
fn into_request_enum(self) -> crate::Request {
crate::Request::Move(self.from_or_range, self.to)
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::Move(from_or_range, to) => Some(MoveRequest { from_or_range, to }),
_ => None,
}
}
fn serialize(&self) -> String {
format!("{} {} {}", Self::COMMAND, self.from_or_range, self.to)
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let from_or_range = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let from_or_range = from_or_range
.parse()
@@ -38,11 +47,11 @@ impl Command for Move {
Ok(MoveRequest { from_or_range, to })
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
debug_assert!(parts.is_empty());
Ok(())
}
}
empty_command_response!(Move);
impl Command<'_, '_> for Move {
type Request = MoveRequest;
type Response = MoveResponse;
}
+23 -14
View File
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseAttributes, ResponseParserError},
commands::{Command, CommandRequest, RequestParserError, empty_command_response},
common::types::{AbsouluteRelativeSongPosition, SongId},
request_tokenizer::RequestTokenizer,
};
@@ -14,16 +14,25 @@ pub struct MoveIdRequest {
pub to: AbsouluteRelativeSongPosition,
}
impl Command for MoveId {
type Request = MoveIdRequest;
type Response = ();
impl CommandRequest<'_> for MoveIdRequest {
const COMMAND: &'static str = "moveid";
fn serialize_request(&self, request: Self::Request) -> String {
format!("{} {} {}", Self::COMMAND, request.id, request.to)
fn into_request_enum(self) -> crate::Request {
crate::Request::MoveId(self.id, self.to)
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::MoveId(id, to) => Some(MoveIdRequest { id, to }),
_ => None,
}
}
fn serialize(&self) -> String {
format!("{} {} {}", Self::COMMAND, self.id, self.to)
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let id = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let id = id
.parse()
@@ -38,11 +47,11 @@ impl Command for MoveId {
Ok(MoveIdRequest { id, to })
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
debug_assert!(parts.is_empty());
Ok(())
}
}
empty_command_response!(MoveId);
impl Command<'_, '_> for MoveId {
type Request = MoveIdRequest;
type Response = MoveIdResponse;
}
+15 -14
View File
@@ -1,28 +1,29 @@
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
request_tokenizer::RequestTokenizer,
commands::{Command, CommandResponse, ResponseParserError, empty_command_request},
response_tokenizer::ResponseAttributes,
};
pub struct Playlist;
impl Command for Playlist {
type Request = ();
type Response = ();
const COMMAND: &'static str = "playlist";
empty_command_request!(Playlist, "playlist");
fn serialize_request(&self, _request: Self::Request) -> String {
Self::COMMAND.to_string()
pub struct PlaylistResponse();
impl CommandResponse<'_> for PlaylistResponse {
fn into_response_enum(self) -> crate::Response {
todo!()
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
debug_assert!(parts.next().is_none());
Ok(())
fn from_response_enum(response: crate::Response) -> Option<Self> {
todo!()
}
fn parse_response(
_parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError<'_>> {
unimplemented!()
}
}
impl Command<'_, '_> for Playlist {
type Request = PlaylistRequest;
type Response = PlaylistResponse;
}
+29 -16
View File
@@ -1,11 +1,10 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, CommandRequest, RequestParserError, empty_command_response},
common::types::{Sort, WindowRange},
filter::Filter,
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
};
pub struct PlaylistFind;
@@ -17,23 +16,36 @@ pub struct PlaylistFindRequest {
window: Option<WindowRange>,
}
impl Command for PlaylistFind {
type Request = PlaylistFindRequest;
type Response = ();
impl CommandRequest<'_> for PlaylistFindRequest {
const COMMAND: &'static str = "playlistfind";
fn serialize_request(&self, request: Self::Request) -> String {
let mut cmd = format!("{} {}", Self::COMMAND, request.filter);
if let Some(sort) = request.sort {
fn into_request_enum(self) -> crate::Request {
crate::Request::PlaylistFind(self.filter, self.sort, self.window)
}
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::PlaylistFind(filter, sort, window) => Some(PlaylistFindRequest {
filter,
sort,
window,
}),
_ => None,
}
}
fn serialize(&self) -> String {
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
if let Some(sort) = &self.sort {
cmd.push_str(&format!(" sort {}", sort));
}
if let Some(window) = request.window {
if let Some(window) = &self.window {
cmd.push_str(&format!(" window {}", window));
}
cmd
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let filter = match parts.next() {
Some(f) => {
Filter::parse(f).map_err(|_| RequestParserError::SyntaxError(1, f.to_owned()))?
@@ -69,10 +81,11 @@ impl Command for PlaylistFind {
window,
})
}
fn parse_response(
_parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
unimplemented!()
}
}
empty_command_response!(PlaylistFind);
impl Command<'_, '_> for PlaylistFind {
type Request = PlaylistFindRequest;
type Response = PlaylistFindResponse;
}
+15 -20
View File
@@ -1,35 +1,30 @@
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, CommandResponse, ResponseParserError, single_item_command_request},
common::types::SongId,
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
};
pub struct PlaylistId;
impl Command for PlaylistId {
type Request = SongId;
type Response = ();
const COMMAND: &'static str = "playlistid";
single_item_command_request!(PlaylistId, "playlistid", SongId);
fn serialize_request(&self, request: Self::Request) -> String {
format!("{} {}", Self::COMMAND, request)
pub struct PlaylistIdResponse();
impl CommandResponse<'_> for PlaylistIdResponse {
fn into_response_enum(self) -> crate::Response {
todo!()
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
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(id)
fn from_response_enum(response: crate::Response) -> Option<Self> {
todo!()
}
fn parse_response(
_parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError<'_>> {
unimplemented!()
}
}
impl Command<'_, '_> for PlaylistId {
type Request = PlaylistIdRequest;
type Response = PlaylistIdResponse;
}
+21 -26
View File
@@ -1,41 +1,36 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{
Command, CommandResponse, RequestParserError, ResponseParserError,
single_optional_item_command_request,
},
common::types::OneOrRange,
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
};
pub struct PlaylistInfo;
impl Command for PlaylistInfo {
type Request = Option<OneOrRange>;
type Response = ();
const COMMAND: &'static str = "playlistinfo";
single_optional_item_command_request!(PlaylistInfo, "playlistinfo", OneOrRange);
fn serialize_request(&self, request: Self::Request) -> String {
match request {
Some(one_or_range) => format!("{} {}", Self::COMMAND, one_or_range),
None => Self::COMMAND.to_string(),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PlaylistInfoResponse;
impl CommandResponse<'_> for PlaylistInfoResponse {
fn into_response_enum(self) -> crate::Response {
todo!()
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
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(one_or_range)
fn from_response_enum(response: crate::Response) -> Option<Self> {
todo!()
}
fn parse_response(
_parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
fn parse(_parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError<'_>> {
unimplemented!()
}
}
impl Command<'_, '_> for PlaylistInfo {
type Request = PlaylistInfoRequest;
type Response = PlaylistInfoResponse;
}
+41 -12
View File
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError},
common::types::{Sort, WindowRange},
filter::Filter,
request_tokenizer::RequestTokenizer,
@@ -17,23 +17,36 @@ pub struct PlaylistSearchRequest {
window: Option<WindowRange>,
}
impl Command for PlaylistSearch {
type Request = PlaylistSearchRequest;
type Response = ();
impl CommandRequest<'_> for PlaylistSearchRequest {
const COMMAND: &'static str = "playlistsearch";
fn serialize_request(&self, request: Self::Request) -> String {
let mut cmd = format!("{} {}", Self::COMMAND, request.filter);
if let Some(sort) = request.sort {
fn into_request_enum(self) -> crate::Request {
crate::Request::PlaylistSearch(self.filter, self.sort, self.window)
}
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::PlaylistSearch(filter, sort, window) => Some(PlaylistSearchRequest {
filter,
sort,
window,
}),
_ => None,
}
}
fn serialize(&self) -> String {
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
if let Some(sort) = &self.sort {
cmd.push_str(&format!(" sort {}", sort));
}
if let Some(window) = request.window {
if let Some(window) = &self.window {
cmd.push_str(&format!(" window {}", window));
}
cmd
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let filter = match parts.next() {
Some(f) => {
Filter::parse(f).map_err(|_| RequestParserError::SyntaxError(1, f.to_owned()))?
@@ -69,10 +82,26 @@ impl Command for PlaylistSearch {
window,
})
}
}
fn parse_response(
_parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PlaylistSearchResponse;
impl CommandResponse<'_> for PlaylistSearchResponse {
fn from_response_enum(response: crate::Response) -> Option<Self> {
todo!()
}
fn into_response_enum(self) -> crate::Response {
todo!()
}
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError<'_>> {
unimplemented!()
}
}
impl Command<'_, '_> for PlaylistSearch {
type Request = PlaylistSearchRequest;
type Response = PlaylistSearchResponse;
}
+39 -12
View File
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError},
common::types::{PlaylistVersion, WindowRange},
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
@@ -15,19 +15,30 @@ pub struct PlChangesRequest {
pub window: Option<WindowRange>,
}
impl Command for PlChanges {
type Request = PlChangesRequest;
type Response = ();
impl CommandRequest<'_> for PlChangesRequest {
const COMMAND: &'static str = "plchanges";
fn serialize_request(&self, request: Self::Request) -> String {
match request.window {
Some(window) => format!("{} {} {}", Self::COMMAND, request.version, window),
None => format!("{} {}", Self::COMMAND, request.version),
fn into_request_enum(self) -> crate::Request {
crate::Request::PlChanges(self.version, self.window)
}
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::PlChanges(version, window) => {
Some(PlChangesRequest { version, window })
}
_ => None,
}
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn serialize(&self) -> String {
match self.window.as_ref() {
Some(window) => format!("{} {} {}", Self::COMMAND, self.version, window),
None => format!("{} {}", Self::COMMAND, self.version),
}
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let version = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let version = version
.parse()
@@ -45,10 +56,26 @@ impl Command for PlChanges {
Ok(PlChangesRequest { version, window })
}
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PlChangesResponse;
impl CommandResponse<'_> for PlChangesResponse {
fn from_response_enum(response: crate::Response) -> Option<Self> {
todo!()
}
fn into_response_enum(self) -> crate::Response {
todo!()
}
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError<'_>> {
unimplemented!()
}
}
impl Command<'_, '_> for PlChanges {
type Request = PlChangesRequest;
type Response = PlChangesResponse;
}
+39 -12
View File
@@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError},
common::types::{PlaylistVersion, WindowRange},
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
@@ -15,19 +15,30 @@ pub struct PlChangesPosIdRequest {
pub window: Option<WindowRange>,
}
impl Command for PlChangesPosId {
type Request = PlChangesPosIdRequest;
type Response = ();
impl CommandRequest<'_> for PlChangesPosIdRequest {
const COMMAND: &'static str = "plchangesposid";
fn serialize_request(&self, request: Self::Request) -> String {
match request.window {
Some(window) => format!("{} {} {}", Self::COMMAND, request.version, window),
None => format!("{} {}", Self::COMMAND, request.version),
fn into_request_enum(self) -> crate::Request {
crate::Request::PlChangesPosId(self.version, self.window)
}
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::PlChangesPosId(version, window) => {
Some(PlChangesPosIdRequest { version, window })
}
_ => None,
}
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn serialize(&self) -> String {
match self.window.as_ref() {
Some(window) => format!("{} {} {}", Self::COMMAND, self.version, window),
None => format!("{} {}", Self::COMMAND, self.version),
}
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let version = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let version = version
.parse()
@@ -45,10 +56,26 @@ impl Command for PlChangesPosId {
Ok(PlChangesPosIdRequest { version, window })
}
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PlChangesPosIdResponse;
impl CommandResponse<'_> for PlChangesPosIdResponse {
fn from_response_enum(response: crate::Response) -> Option<Self> {
todo!()
}
fn into_response_enum(self) -> crate::Response {
todo!()
}
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError<'_>> {
unimplemented!()
}
}
impl Command<'_, '_> for PlChangesPosId {
type Request = PlChangesPosIdRequest;
type Response = PlChangesPosIdResponse;
}
+23 -15
View File
@@ -1,10 +1,9 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, CommandRequest, RequestParserError, empty_command_response},
common::types::{Priority, WindowRange},
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
};
pub struct Prio;
@@ -15,16 +14,25 @@ pub struct PrioRequest {
pub window: WindowRange,
}
impl Command for Prio {
type Request = PrioRequest;
type Response = ();
impl CommandRequest<'_> for PrioRequest {
const COMMAND: &'static str = "prio";
fn serialize_request(&self, request: Self::Request) -> String {
format!("{} {} {}", Self::COMMAND, request.prio, request.window)
fn into_request_enum(self) -> crate::Request {
crate::Request::Prio(self.prio, self.window)
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::Prio(prio, window) => Some(PrioRequest { prio, window }),
_ => None,
}
}
fn serialize(&self) -> String {
format!("{} {} {}", Self::COMMAND, self.prio, self.window)
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let prio = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let prio = prio
.parse()
@@ -39,11 +47,11 @@ impl Command for Prio {
Ok(PrioRequest { prio, window })
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
debug_assert!(parts.is_empty());
Ok(())
}
}
empty_command_response!(Prio);
impl Command<'_, '_> for Prio {
type Request = PrioRequest;
type Response = PrioResponse;
}
+25 -18
View File
@@ -1,10 +1,9 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, CommandRequest, RequestParserError, empty_command_response},
common::types::{Priority, SongId},
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
};
pub struct PrioId;
@@ -15,46 +14,54 @@ pub struct PrioIdRequest {
pub songids: Vec<SongId>,
}
impl Command for PrioId {
type Request = PrioIdRequest;
type Response = ();
impl CommandRequest<'_> for PrioIdRequest {
const COMMAND: &'static str = "prioid";
fn serialize_request(&self, request: Self::Request) -> String {
let songids = request
fn into_request_enum(self) -> crate::Request {
crate::Request::PrioId(self.prio, self.songids)
}
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::PrioId(prio, songids) => Some(PrioIdRequest { prio, songids }),
_ => None,
}
}
fn serialize(&self) -> String {
let songids = self
.songids
.iter()
.map(|id| id.to_string())
.collect::<Vec<String>>()
.join(",");
format!("{} {} {}", Self::COMMAND, request.prio, songids)
format!("{} {} {}", Self::COMMAND, self.prio, songids)
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
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>>()?;
.collect::<Result<Vec<SongId>, RequestParserError>>()?;
debug_assert!(parts.next().is_none());
Ok(PrioIdRequest { prio, songids })
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
debug_assert!(parts.is_empty());
Ok(())
}
}
empty_command_response!(PrioId);
impl Command<'_, '_> for PrioId {
type Request = PrioIdRequest;
type Response = PrioIdResponse;
}
+26 -20
View File
@@ -1,10 +1,9 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, CommandRequest, RequestParserError, empty_command_response},
common::types::{SongId, TimeInterval},
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
};
pub struct RangeId;
@@ -15,21 +14,28 @@ pub struct RangeIdRequest {
time_interval: TimeInterval,
}
impl Command for RangeId {
type Request = RangeIdRequest;
type Response = ();
impl CommandRequest<'_> for RangeIdRequest {
const COMMAND: &'static str = "rangeid";
fn serialize_request(&self, request: Self::Request) -> String {
format!(
"{} {} {}",
Self::COMMAND,
request.songid,
request.time_interval
)
fn into_request_enum(self) -> crate::Request {
crate::Request::RangeId(self.songid, self.time_interval)
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::RangeId(songid, time_interval) => Some(RangeIdRequest {
songid,
time_interval,
}),
_ => None,
}
}
fn serialize(&self) -> String {
format!("{} {} {}", Self::COMMAND, self.songid, self.time_interval)
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let songid = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songid = songid
.parse()
@@ -47,11 +53,11 @@ impl Command for RangeId {
time_interval,
})
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
debug_assert!(parts.is_empty());
Ok(())
}
}
empty_command_response!(RangeId);
impl Command<'_, '_> for RangeId {
type Request = RangeIdRequest;
type Response = RangeIdResponse;
}
+8 -34
View File
@@ -1,43 +1,17 @@
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{
Command, RequestParserError, empty_command_response, single_optional_item_command_request,
},
common::types::OneOrRange,
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
};
pub struct Shuffle;
impl Command for Shuffle {
type Request = Option<OneOrRange>;
type Response = ();
const COMMAND: &'static str = "shuffle";
single_optional_item_command_request!(Shuffle, "shuffle", OneOrRange);
fn serialize_request(&self, request: Self::Request) -> String {
match request {
Some(range) => format!("{} {}", Self::COMMAND, range),
None => Self::COMMAND.to_string(),
}
}
empty_command_response!(Shuffle);
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
let range = parts
.next()
.map(|range| {
range
.parse()
.map_err(|_| RequestParserError::SyntaxError(0, range.to_string()))
})
.transpose()?;
debug_assert!(parts.next().is_none());
Ok(range)
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
debug_assert!(parts.is_empty());
Ok(())
}
impl Command<'_, '_> for Shuffle {
type Request = ShuffleRequest;
type Response = ShuffleResponse;
}
+23 -20
View File
@@ -1,10 +1,9 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, CommandRequest, RequestParserError, empty_command_response},
common::types::SongPosition,
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
};
pub struct Swap;
@@ -15,21 +14,25 @@ pub struct SwapRequest {
pub songpos2: SongPosition,
}
impl Command for Swap {
type Request = SwapRequest;
type Response = ();
impl CommandRequest<'_> for SwapRequest {
const COMMAND: &'static str = "swap";
fn serialize_request(&self, request: Self::Request) -> String {
format!(
"{} {} {}",
Self::COMMAND,
request.songpos1,
request.songpos2
)
fn into_request_enum(self) -> crate::Request {
crate::Request::Swap(self.songpos1, self.songpos2)
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::Swap(songpos1, songpos2) => Some(SwapRequest { songpos1, songpos2 }),
_ => None,
}
}
fn serialize(&self) -> String {
format!("{} {} {}", Self::COMMAND, self.songpos1, self.songpos2)
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let songpos1 = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songpos1 = songpos1
.parse()
@@ -44,11 +47,11 @@ impl Command for Swap {
Ok(SwapRequest { songpos1, songpos2 })
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
debug_assert!(parts.is_empty());
Ok(())
}
}
empty_command_response!(Swap);
impl Command<'_, '_> for Swap {
type Request = SwapRequest;
type Response = SwapResponse;
}
+23 -15
View File
@@ -1,10 +1,9 @@
use serde::{Deserialize, Serialize};
use crate::{
commands::{Command, RequestParserError, ResponseParserError},
commands::{Command, CommandRequest, RequestParserError, empty_command_response},
common::types::SongId,
request_tokenizer::RequestTokenizer,
response_tokenizer::ResponseAttributes,
};
pub struct SwapId;
@@ -15,16 +14,25 @@ pub struct SwapIdRequest {
pub songid2: SongId,
}
impl Command for SwapId {
type Request = SwapIdRequest;
type Response = ();
impl CommandRequest<'_> for SwapIdRequest {
const COMMAND: &'static str = "swapid";
fn serialize_request(&self, request: Self::Request) -> String {
format!("{} {} {}", Self::COMMAND, request.songid1, request.songid2)
fn into_request_enum(self) -> crate::Request {
crate::Request::SwapId(self.songid1, self.songid2)
}
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
fn from_request_enum(request: crate::Request) -> Option<Self> {
match request {
crate::Request::SwapId(songid1, songid2) => Some(SwapIdRequest { songid1, songid2 }),
_ => None,
}
}
fn serialize(&self) -> String {
format!("{} {} {}", Self::COMMAND, self.songid1, self.songid2)
}
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
let songid1 = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
let songid1 = songid1
.parse()
@@ -39,11 +47,11 @@ impl Command for SwapId {
Ok(SwapIdRequest { songid1, songid2 })
}
fn parse_response(
parts: ResponseAttributes<'_>,
) -> Result<Self::Response, ResponseParserError<'_>> {
debug_assert!(parts.is_empty());
Ok(())
}
}
empty_command_response!(SwapId);
impl Command<'_, '_> for SwapId {
type Request = SwapIdRequest;
type Response = SwapIdResponse;
}