Compare commits
1 Commits
main
...
split-comm
| Author | SHA1 | Date | |
|---|---|---|---|
|
ba116b5d3e
|
@@ -13,6 +13,7 @@ rust-version = "1.85.0"
|
||||
[dependencies]
|
||||
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"] }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
369
src/commands.rs
369
src/commands.rs
@@ -28,73 +28,342 @@ pub use reflection::*;
|
||||
pub use stickers::*;
|
||||
pub use stored_playlists::*;
|
||||
|
||||
/// A trait modelling the request/response pair of a single MPD command.
|
||||
pub trait Command {
|
||||
/// The request sent from the client to the server
|
||||
type Request;
|
||||
|
||||
/// The response sent from the server to the client
|
||||
type Response;
|
||||
|
||||
/// A trait modelling a single MPD command request.
|
||||
pub trait CommandRequest<'a>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
/// The command name used within the protocol
|
||||
const COMMAND: &'static str;
|
||||
|
||||
/// Converts this specific request type to it's corresponding variant in the generic Request enum.
|
||||
fn into_request_enum(self) -> Request;
|
||||
|
||||
/// Converts from the generic Request enum to this specific request type.
|
||||
///
|
||||
/// If the enum variant does not match this type, returns None.
|
||||
fn from_request_enum(request: Request) -> Option<Self>;
|
||||
|
||||
/// Serializes the request into a String.
|
||||
fn serialize(&self) -> String;
|
||||
|
||||
/// Parses the request from its tokenized parts.
|
||||
/// See also [`parse_raw`].
|
||||
fn parse(parts: RequestTokenizer<'a>) -> Result<Self, RequestParserError>;
|
||||
|
||||
/// Parses the request from its raw string representation.
|
||||
///
|
||||
/// This assumes the raw string starts with the command name, e.g.
|
||||
/// `command_name arg1 "arg2 arg3"`
|
||||
fn parse_raw(raw: &'a str) -> Result<Self, RequestParserError> {
|
||||
let (line, rest) = raw
|
||||
.split_once('\n')
|
||||
.ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
|
||||
debug_assert!(rest.is_empty());
|
||||
|
||||
let mut tokenized = RequestTokenizer::new(line);
|
||||
|
||||
let command_name_token_length = Self::COMMAND.split_ascii_whitespace().count();
|
||||
let mut command_name = Vec::with_capacity(command_name_token_length);
|
||||
for _ in 0..command_name_token_length {
|
||||
let token = tokenized
|
||||
.next()
|
||||
.ok_or(RequestParserError::SyntaxError(0, line.to_string()))?;
|
||||
command_name.push(token);
|
||||
}
|
||||
let command_name = command_name.join(" ");
|
||||
|
||||
if command_name != Self::COMMAND {
|
||||
return Err(RequestParserError::SyntaxError(0, line.to_string()));
|
||||
}
|
||||
|
||||
Self::parse(tokenized)
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait modelling a single MPD command response.
|
||||
pub trait CommandResponse<'a>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
/// Converts this specific response type to it's corresponding variant in the generic Response enum.
|
||||
fn into_response_enum(self) -> crate::Response;
|
||||
|
||||
/// Converts from the generic Response enum to this specific response type.
|
||||
///
|
||||
/// If the enum variant does not match this type, returns None.
|
||||
fn from_response_enum(response: crate::Response) -> Option<Self>;
|
||||
|
||||
/// Serializes the response into a Vec<u8>.
|
||||
// fn serialize(&self) -> Vec<u8>;
|
||||
|
||||
/// Parses the response from its tokenized parts.
|
||||
/// See also [`parse_raw`].
|
||||
fn parse(parts: ResponseAttributes<'a>) -> Result<Self, ResponseParserError<'a>>;
|
||||
|
||||
/// Parses the response from its raw byte representation.
|
||||
fn parse_raw(raw: &'a [u8]) -> Result<Self, ResponseParserError<'a>> {
|
||||
Self::parse(ResponseAttributes::new_from_bytes(raw))
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait modelling the request/response pair of a single MPD command.
|
||||
pub trait Command<'req, 'res> {
|
||||
/// The request sent from the client to the server
|
||||
type Request: CommandRequest<'req>;
|
||||
/// The response sent from the server to the client
|
||||
type Response: CommandResponse<'res>;
|
||||
|
||||
/// The command name used within the protocol
|
||||
const COMMAND: &'static str = Self::Request::COMMAND;
|
||||
|
||||
/// Serialize the request into a string.
|
||||
/// This should optimally produce an input that can be parsed by [`parse_request`]
|
||||
fn serialize_request(&self, request: Self::Request) -> String;
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
request.serialize().to_owned()
|
||||
}
|
||||
/// Serialize the request into a bytestring.
|
||||
fn serialize_request_to_bytes(&self, request: Self::Request) -> Vec<u8> {
|
||||
self.serialize_request(request).into_bytes()
|
||||
}
|
||||
|
||||
// fn serialize_response(&self) -> String;
|
||||
// fn serialize_response_to_bytes(&self) -> Vec<u8> {
|
||||
// self.serialize_response().into_bytes()
|
||||
// }
|
||||
|
||||
/// Parse the request from its tokenized parts.
|
||||
///
|
||||
/// Note that this assumes only the parts after the command name are passed in, e.g.
|
||||
///
|
||||
/// ```ignore
|
||||
/// arg1 "arg2 arg3"
|
||||
/// ```
|
||||
fn parse_request(parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError>;
|
||||
|
||||
/// Parse the raw request string into a request and the remaining unparsed string.
|
||||
/// This assumes the raw string starts with the command name, e.g.
|
||||
///
|
||||
/// ```ignore
|
||||
/// command_name arg1 "arg2 arg3"
|
||||
/// ```
|
||||
fn parse_raw_request(raw: &str) -> Result<(Self::Request, &str), RequestParserError> {
|
||||
let (line, rest) = raw
|
||||
.split_once('\n')
|
||||
.ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
let mut tokenized = RequestTokenizer::new(line);
|
||||
|
||||
let command_name = tokenized
|
||||
.next()
|
||||
.ok_or(RequestParserError::SyntaxError(0, line.to_string()))?
|
||||
.trim();
|
||||
|
||||
debug_assert!(command_name == Self::COMMAND);
|
||||
|
||||
Self::parse_request(tokenized).map(|req| (req, rest))
|
||||
/// Parse the request from its tokenized parts. See also [`parse_raw_request`].
|
||||
fn parse_request(parts: RequestTokenizer<'req>) -> Result<Self::Request, RequestParserError> {
|
||||
Self::Request::parse(parts)
|
||||
}
|
||||
|
||||
/// Parse the response from its tokenized parts.
|
||||
/// See also [`parse_raw_response`].
|
||||
fn parse_response(parts: ResponseAttributes<'_>) -> ResponseParserResult<'_, Self::Response>;
|
||||
/// Parse the raw request string into a request.
|
||||
/// This assumes the raw string starts with the command name, e.g. `command_name arg1 "arg2 arg3"`
|
||||
fn parse_raw_request(raw: &'req str) -> Result<Self::Request, RequestParserError> {
|
||||
Self::Request::parse_raw(raw)
|
||||
}
|
||||
|
||||
/// Serialize the response into a string.
|
||||
// fn serialize_response(&self, response: Self::Response) -> String {
|
||||
|
||||
/// Parse the response from its tokenized parts. See also [`parse_raw_response`].
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'res>,
|
||||
) -> Result<Self::Response, ResponseParserError<'res>> {
|
||||
Self::Response::parse(parts)
|
||||
}
|
||||
/// Parse the raw response string into a response.
|
||||
fn parse_raw_response(raw: &str) -> ResponseParserResult<'_, Self::Response> {
|
||||
Self::parse_response(ResponseAttributes::new(raw))
|
||||
fn parse_raw_response(raw: &'res [u8]) -> Result<Self::Response, ResponseParserError<'res>> {
|
||||
Self::Response::parse_raw(raw)
|
||||
}
|
||||
}
|
||||
|
||||
// pub type RequestParserResult<'a> = ;
|
||||
/// Request/response implementation helpers
|
||||
|
||||
macro_rules! empty_command_request {
|
||||
($name:ident, $command_name:expr) => {
|
||||
paste::paste! {
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct [<$name Request>];
|
||||
}
|
||||
|
||||
impl crate::commands::CommandRequest<'_> for paste::paste! { [<$name Request>] } {
|
||||
const COMMAND: &'static str = $command_name;
|
||||
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
match Self::COMMAND {
|
||||
$command_name => crate::Request::$name,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match (Self::COMMAND, request) {
|
||||
($command_name, crate::Request::$name) => {
|
||||
Some(paste::paste! { [<$name Request>] })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
|
||||
fn parse(
|
||||
mut parts: crate::commands::RequestTokenizer<'_>,
|
||||
) -> Result<Self, crate::commands::RequestParserError> {
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(paste::paste! { [<$name Request>] })
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! empty_command_response {
|
||||
($name:ident) => {
|
||||
paste::paste! {
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct [<$name Response>];
|
||||
}
|
||||
|
||||
impl crate::commands::CommandResponse<'_> for paste::paste! { [<$name Response>] } {
|
||||
fn into_response_enum(self) -> crate::Response {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn from_response_enum(_response: crate::Response) -> Option<Self> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn parse(
|
||||
_parts: crate::commands::ResponseAttributes<'_>,
|
||||
) -> Result<Self, crate::commands::ResponseParserError<'_>> {
|
||||
debug_assert!(_parts.is_empty());
|
||||
Ok(paste::paste! { [<$name Response>] })
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! single_item_command_request {
|
||||
($name:ident, $command_name:expr, $item_type:ty) => {
|
||||
paste::paste! {
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct [<$name Request>] ($item_type);
|
||||
}
|
||||
|
||||
impl crate::commands::CommandRequest<'_> for paste::paste! { [<$name Request>] } {
|
||||
const COMMAND: &'static str = $command_name;
|
||||
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
match Self::COMMAND {
|
||||
$command_name => crate::Request::$name(self.0),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match (Self::COMMAND, request) {
|
||||
($command_name, crate::Request::$name(item)) => {
|
||||
Some(paste::paste! { [<$name Request>] ( item ) })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
format!("{} {}", Self::COMMAND, self.0)
|
||||
}
|
||||
|
||||
fn parse(
|
||||
mut parts: crate::commands::RequestTokenizer<'_>,
|
||||
) -> Result<Self, crate::commands::RequestParserError> {
|
||||
let item_token = parts
|
||||
.next()
|
||||
.ok_or(crate::commands::RequestParserError::UnexpectedEOF)?;
|
||||
let item = item_token.parse::<$item_type>().map_err(|_| {
|
||||
crate::commands::RequestParserError::SyntaxError(0, item_token.to_owned())
|
||||
})?;
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(paste::paste! { [<$name Request>] ( item ) })
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! single_item_command_response {
|
||||
($name:ident, $item_name:expr, $item_type:ty) => {
|
||||
paste::paste! {
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct [<$name Response>] ( $item_type );
|
||||
}
|
||||
|
||||
impl crate::commands::CommandResponse<'_> for paste::paste! { [<$name Response>] } {
|
||||
fn into_response_enum(self) -> crate::Response {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn from_response_enum(_response: crate::Response) -> Option<Self> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn parse(
|
||||
parts: crate::commands::ResponseAttributes<'_>,
|
||||
) -> Result<Self, crate::commands::ResponseParserError<'_>> {
|
||||
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),
|
||||
)?;
|
||||
let item_ = crate::response_tokenizer::expect_property_type!(
|
||||
Some(item_token),
|
||||
$item_name,
|
||||
Text
|
||||
);
|
||||
let item = item_.parse::<$item_type>().map_err(|_| {
|
||||
crate::commands::ResponseParserError::InvalidProperty($item_name, item_)
|
||||
})?;
|
||||
|
||||
Ok(paste::paste! { [<$name Response>] ( item ) })
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! multi_item_command_response {
|
||||
($name:ident, $item_name:expr, $item_type:ty) => {
|
||||
paste::paste! {
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct [<$name Response>] ( Vec<$item_type> );
|
||||
}
|
||||
|
||||
impl crate::commands::CommandResponse<'_> for paste::paste! { [<$name Response>] } {
|
||||
fn into_response_enum(self) -> crate::Response {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn from_response_enum(_response: crate::Response) -> Option<Self> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn parse(
|
||||
mut parts: crate::commands::ResponseAttributes<'_>,
|
||||
) -> Result<Self, crate::commands::ResponseParserError<'_>> {
|
||||
let parts_: Vec<_> = parts.into_vec()?;
|
||||
|
||||
if let Some((k, _)) = parts_.iter().find(|(k, _)| *k != $item_name) {
|
||||
return Err(ResponseParserError::UnexpectedProperty(k));
|
||||
}
|
||||
|
||||
let mut items = Vec::with_capacity(parts_.len());
|
||||
|
||||
while let Some(value) = parts_.into_iter().next() {
|
||||
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,
|
||||
)
|
||||
})?;
|
||||
|
||||
items.push(parsed_value);
|
||||
}
|
||||
|
||||
Ok(paste::paste! { [<$name Response>] ( items ) })
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use empty_command_request;
|
||||
pub(crate) use empty_command_response;
|
||||
pub(crate) use multi_item_command_response;
|
||||
pub(crate) use single_item_command_request;
|
||||
pub(crate) use single_item_command_response;
|
||||
|
||||
///
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum RequestParserError {
|
||||
|
||||
@@ -4,8 +4,8 @@ pub mod outputs;
|
||||
pub mod outputset;
|
||||
pub mod toggleoutput;
|
||||
|
||||
pub use disableoutput::DisableOutput;
|
||||
pub use enableoutput::EnableOutput;
|
||||
pub use outputs::Outputs;
|
||||
pub use outputset::OutputSet;
|
||||
pub use toggleoutput::ToggleOutput;
|
||||
pub use disableoutput::*;
|
||||
pub use enableoutput::*;
|
||||
pub use outputs::*;
|
||||
pub use outputset::*;
|
||||
pub use toggleoutput::*;
|
||||
|
||||
@@ -1,38 +1,15 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{Command, empty_command_response, single_item_command_request},
|
||||
common::types::AudioOutputId,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct DisableOutput;
|
||||
|
||||
pub type DisableOutputRequest = AudioOutputId;
|
||||
single_item_command_request!(DisableOutput, "disableoutput", AudioOutputId);
|
||||
|
||||
impl Command for DisableOutput {
|
||||
empty_command_response!(DisableOutput);
|
||||
|
||||
impl Command<'_, '_> for DisableOutput {
|
||||
type Request = DisableOutputRequest;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "disableoutput";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let output_id = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
let output_id = output_id
|
||||
.parse()
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, output_id.to_owned()))?;
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(output_id)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
type Response = DisableOutputResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError,
|
||||
empty_command_response, single_item_command_request,
|
||||
},
|
||||
common::types::AudioOutputId,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,32 +10,11 @@ use crate::{
|
||||
|
||||
pub struct EnableOutput;
|
||||
|
||||
pub type EnableOutputRequest = AudioOutputId;
|
||||
single_item_command_request!(EnableOutput, "enableoutput", AudioOutputId);
|
||||
|
||||
impl Command for EnableOutput {
|
||||
empty_command_response!(EnableOutput);
|
||||
|
||||
impl Command<'_, '_> for EnableOutput {
|
||||
type Request = EnableOutputRequest;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "enableoutput";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let output_id = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
let output_id = output_id
|
||||
.parse()
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, output_id.to_owned()))?;
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(output_id)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
type Response = EnableOutputResponse;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@ use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError,
|
||||
empty_command_request,
|
||||
},
|
||||
common::types::AudioOutputId,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{ResponseAttributes, expect_property_type},
|
||||
@@ -11,6 +14,8 @@ use crate::{
|
||||
|
||||
pub struct Outputs;
|
||||
|
||||
empty_command_request!(Outputs, "outputs");
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Output {
|
||||
pub id: AudioOutputId,
|
||||
@@ -22,23 +27,16 @@ pub struct Output {
|
||||
|
||||
pub type OutputsResponse = Vec<Output>;
|
||||
|
||||
impl Command for Outputs {
|
||||
type Request = ();
|
||||
type Response = OutputsResponse;
|
||||
const COMMAND: &'static str = "outputs";
|
||||
|
||||
fn serialize_request(&self, _: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
impl CommandResponse<'_> for OutputsResponse {
|
||||
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<'_>> {
|
||||
let mut outputs = Vec::new();
|
||||
|
||||
let mut id: Option<AudioOutputId> = None;
|
||||
@@ -118,6 +116,11 @@ impl Command for Outputs {
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<'_, '_> for Outputs {
|
||||
type Request = OutputsRequest;
|
||||
type Response = OutputsResponse;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use indoc::indoc;
|
||||
@@ -138,7 +141,7 @@ mod tests {
|
||||
attribute: fifo_path=/tmp/empidee-visualizer.fifo
|
||||
OK
|
||||
"};
|
||||
let result = Outputs::parse_raw_response(input);
|
||||
let result = Outputs::parse_raw_response(input.as_bytes());
|
||||
assert_eq!(
|
||||
result,
|
||||
Ok(vec![
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError,
|
||||
empty_command_response,
|
||||
},
|
||||
common::types::AudioOutputId,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -16,22 +19,37 @@ pub struct OutputSetRequest {
|
||||
pub attribute_value: String,
|
||||
}
|
||||
|
||||
impl Command for OutputSet {
|
||||
type Request = OutputSetRequest;
|
||||
type Response = ();
|
||||
impl CommandRequest<'_> for OutputSetRequest {
|
||||
const COMMAND: &'static str = "outputset";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::OutputSet(self.output_id, self.attribute_name, self.attribute_value)
|
||||
}
|
||||
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::OutputSet(output_id, attribute_name, attribute_value) => {
|
||||
Some(OutputSetRequest {
|
||||
output_id,
|
||||
attribute_name,
|
||||
attribute_value,
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
format!(
|
||||
"{} {} {} {}",
|
||||
Self::COMMAND,
|
||||
request.output_id,
|
||||
request.attribute_name,
|
||||
request.attribute_value
|
||||
self.output_id,
|
||||
self.attribute_name,
|
||||
self.attribute_value
|
||||
)
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let output_id = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
let output_id = output_id
|
||||
.parse()
|
||||
@@ -47,11 +65,11 @@ impl Command for OutputSet {
|
||||
attribute_value: attribute_value.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(OutputSet);
|
||||
|
||||
impl Command<'_, '_> for OutputSet {
|
||||
type Request = OutputSetRequest;
|
||||
type Response = OutputSetResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError,
|
||||
empty_command_response, single_item_command_request,
|
||||
},
|
||||
common::types::AudioOutputId,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,32 +10,11 @@ use crate::{
|
||||
|
||||
pub struct ToggleOutput;
|
||||
|
||||
pub type ToggleOutputRequest = AudioOutputId;
|
||||
single_item_command_request!(ToggleOutput, "toggleoutput", AudioOutputId);
|
||||
|
||||
impl Command for ToggleOutput {
|
||||
empty_command_response!(ToggleOutput);
|
||||
|
||||
impl Command<'_, '_> for ToggleOutput {
|
||||
type Request = ToggleOutputRequest;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "toggleoutput";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let output_id = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
let output_id = output_id
|
||||
.parse()
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, output_id.to_owned()))?;
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(output_id)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
type Response = ToggleOutputResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError,
|
||||
empty_command_request,
|
||||
},
|
||||
common::types::ChannelName,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{ResponseAttributes, expect_property_type},
|
||||
@@ -9,29 +12,23 @@ use crate::{
|
||||
|
||||
pub struct Channels;
|
||||
|
||||
empty_command_request!(Channels, "channels");
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ChannelsResponse {
|
||||
pub channels: Vec<ChannelName>,
|
||||
}
|
||||
|
||||
impl Command for Channels {
|
||||
type Request = ();
|
||||
type Response = ChannelsResponse;
|
||||
const COMMAND: &'static str = "channels";
|
||||
|
||||
fn serialize_request(&self, _: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
impl<'a> CommandResponse<'a> for ChannelsResponse {
|
||||
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<'_>> {
|
||||
let parts: Vec<_> = parts.into_vec()?;
|
||||
let mut channel_names = Vec::with_capacity(parts.len());
|
||||
for (key, value) in parts {
|
||||
@@ -49,6 +46,11 @@ impl Command for Channels {
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<'_, '_> for Channels {
|
||||
type Request = ChannelsRequest;
|
||||
type Response = ChannelsResponse;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -63,7 +65,7 @@ mod tests {
|
||||
channels: baz
|
||||
OK
|
||||
"};
|
||||
let response = Channels::parse_raw_response(response).unwrap();
|
||||
let response = Channels::parse_raw_response(response.as_bytes()).unwrap();
|
||||
assert_eq!(
|
||||
response,
|
||||
ChannelsResponse {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError,
|
||||
empty_command_request,
|
||||
},
|
||||
common::types::ChannelName,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{ResponseAttributes, expect_property_type},
|
||||
@@ -9,7 +12,10 @@ use crate::{
|
||||
|
||||
pub struct ReadMessages;
|
||||
|
||||
pub type ReadMessagesResponse = Vec<ReadMessagesResponseEntry>;
|
||||
empty_command_request!(ReadMessages, "readmessages");
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ReadMessagesResponse(Vec<ReadMessagesResponseEntry>);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ReadMessagesResponseEntry {
|
||||
@@ -17,24 +23,16 @@ pub struct ReadMessagesResponseEntry {
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl Command for ReadMessages {
|
||||
type Request = ();
|
||||
type Response = ReadMessagesResponse;
|
||||
const COMMAND: &'static str = "readmessages";
|
||||
|
||||
fn serialize_request(&self, _: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
impl CommandResponse<'_> for ReadMessagesResponse {
|
||||
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<'_>> {
|
||||
let parts: Vec<_> = parts.into_vec()?;
|
||||
debug_assert!(parts.len() % 2 == 0);
|
||||
|
||||
@@ -57,10 +55,15 @@ impl Command for ReadMessages {
|
||||
messages.push(ReadMessagesResponseEntry { channel, message });
|
||||
}
|
||||
|
||||
Ok(messages)
|
||||
Ok(ReadMessagesResponse(messages))
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<'_, '_> for ReadMessages {
|
||||
type Request = ReadMessagesRequest;
|
||||
type Response = ReadMessagesResponse;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use indoc::indoc;
|
||||
@@ -76,10 +79,10 @@ mod tests {
|
||||
message: message2
|
||||
OK
|
||||
"};
|
||||
let result = ReadMessages::parse_raw_response(input);
|
||||
let result = ReadMessages::parse_raw_response(input.as_bytes());
|
||||
assert_eq!(
|
||||
result,
|
||||
Ok(vec![
|
||||
Ok(ReadMessagesResponse(vec![
|
||||
ReadMessagesResponseEntry {
|
||||
channel: "channel1".parse().unwrap(),
|
||||
message: "message1".to_string(),
|
||||
@@ -88,7 +91,7 @@ mod tests {
|
||||
channel: "channel2".parse().unwrap(),
|
||||
message: "message2".to_string(),
|
||||
},
|
||||
])
|
||||
]))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, CommandResponse, RequestParserError, empty_command_response,
|
||||
},
|
||||
common::types::ChannelName,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -15,16 +17,27 @@ pub struct SendMessageRequest {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl Command for SendMessage {
|
||||
type Request = SendMessageRequest;
|
||||
type Response = ();
|
||||
impl CommandRequest<'_> for SendMessageRequest {
|
||||
const COMMAND: &'static str = "sendmessage";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {} {}", Self::COMMAND, request.channel, request.message)
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::SendMessage(self.channel, self.message)
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::SendMessage(channel, message) => {
|
||||
Some(SendMessageRequest { channel, message })
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
format!("{} {} {}", Self::COMMAND, self.channel, self.message)
|
||||
}
|
||||
|
||||
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let channel = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
let channel = channel
|
||||
.parse()
|
||||
@@ -37,11 +50,11 @@ impl Command for SendMessage {
|
||||
|
||||
Ok(SendMessageRequest { channel, message })
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(SendMessage);
|
||||
|
||||
impl Command<'_, '_> for SendMessage {
|
||||
type Request = SendMessageRequest;
|
||||
type Response = SendMessageResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::ChannelName,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,30 +10,11 @@ use crate::{
|
||||
|
||||
pub struct Subscribe;
|
||||
|
||||
impl Command for Subscribe {
|
||||
type Request = ChannelName;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "subscribe";
|
||||
single_item_command_request!(Subscribe, "subscribe", ChannelName);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(Subscribe);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let channel_name = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
let channel_name = channel_name
|
||||
.parse()
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, channel_name.to_owned()))?;
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(channel_name)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for Subscribe {
|
||||
type Request = SubscribeRequest;
|
||||
type Response = SubscribeResponse;
|
||||
}
|
||||
|
||||
@@ -1,36 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single, single_item_command_request,
|
||||
},
|
||||
common::types::ChannelName,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct Unsubscribe;
|
||||
|
||||
impl Command for Unsubscribe {
|
||||
type Request = ChannelName;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "unsubscribe";
|
||||
single_item_command_request!(Unsubscribe, "unsubscribe", ChannelName);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(Unsubscribe);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let channel_name = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
let channel_name = channel_name
|
||||
.parse()
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, channel_name.to_owned()))?;
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(channel_name)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for Unsubscribe {
|
||||
type Request = UnsubscribeRequest;
|
||||
type Response = UnsubscribeResponse;
|
||||
}
|
||||
|
||||
@@ -1,33 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response, single_item_command_request,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct BinaryLimit;
|
||||
|
||||
impl Command for BinaryLimit {
|
||||
type Request = u64;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "binarylimit";
|
||||
single_item_command_request!(BinaryLimit, "binarylimit", u64);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(BinaryLimit);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let limit = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
let limit = limit
|
||||
.parse()
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, limit.to_string()))?;
|
||||
debug_assert!(parts.next().is_none());
|
||||
Ok(limit)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for BinaryLimit {
|
||||
type Request = BinaryLimitRequest;
|
||||
type Response = BinaryLimitResponse;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct Close;
|
||||
|
||||
impl Command for Close {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "close";
|
||||
empty_command_request!(Close, "close");
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
empty_command_response!(Close);
|
||||
|
||||
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 Close {
|
||||
type Request = CloseRequest;
|
||||
type Response = CloseResponse;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct Kill;
|
||||
|
||||
impl Command for Kill {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "kill";
|
||||
empty_command_request!(Kill, "kill");
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
empty_command_response!(Kill);
|
||||
|
||||
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 Kill {
|
||||
type Request = KillRequest;
|
||||
type Response = KillResponse;
|
||||
}
|
||||
|
||||
@@ -1,33 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response, single_item_command_request,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct Password;
|
||||
|
||||
impl Command for Password {
|
||||
type Request = String;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "password";
|
||||
single_item_command_request!(Password, "password", String);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(Password);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let password = parts
|
||||
.next()
|
||||
.ok_or(RequestParserError::UnexpectedEOF)?
|
||||
.to_string();
|
||||
debug_assert!(parts.next().is_none());
|
||||
Ok(password)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for Password {
|
||||
type Request = PasswordRequest;
|
||||
type Response = PasswordResponse;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct Ping;
|
||||
|
||||
impl Command for Ping {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "ping";
|
||||
empty_command_request!(Ping, "ping");
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
empty_command_response!(Ping);
|
||||
|
||||
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 Ping {
|
||||
type Request = PingRequest;
|
||||
type Response = PingResponse;
|
||||
}
|
||||
|
||||
@@ -1,40 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandResponse, RequestParserError, ResponseParserError, empty_command_request,
|
||||
multi_item_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{ResponseAttributes, expect_property_type},
|
||||
};
|
||||
|
||||
pub struct Protocol;
|
||||
|
||||
pub type ProtocolResponse = Vec<String>;
|
||||
empty_command_request!(Protocol, "protocol");
|
||||
|
||||
impl Command for Protocol {
|
||||
type Request = ();
|
||||
multi_item_command_response!(Protocol, "feature", String);
|
||||
|
||||
impl Command<'_, '_> for Protocol {
|
||||
type Request = ProtocolRequest;
|
||||
type Response = ProtocolResponse;
|
||||
const COMMAND: &'static str = "protocol";
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
|
||||
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<'_>> {
|
||||
let parts_: Vec<_> = parts.into_vec()?;
|
||||
if let Some((k, _)) = parts_.iter().find(|(k, _)| *k != "feature") {
|
||||
return Err(ResponseParserError::UnexpectedProperty(k));
|
||||
}
|
||||
|
||||
let list = parts_
|
||||
.into_iter()
|
||||
.map(|(k, v)| Ok(expect_property_type!(Some(v), k, Text).to_string()))
|
||||
.collect::<Result<Vec<_>, ResponseParserError>>()?;
|
||||
|
||||
Ok(list)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct ProtocolAll;
|
||||
|
||||
impl Command for ProtocolAll {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "protocol all";
|
||||
empty_command_request!(ProtocolAll, "protocol all");
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
empty_command_response!(ProtocolAll);
|
||||
|
||||
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 ProtocolAll {
|
||||
type Request = ProtocolAllRequest;
|
||||
type Response = ProtocolAllResponse;
|
||||
}
|
||||
|
||||
@@ -1,40 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
multi_item_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{ResponseAttributes, expect_property_type},
|
||||
};
|
||||
|
||||
pub struct ProtocolAvailable;
|
||||
|
||||
pub type ProtocolAvailableResponse = Vec<String>;
|
||||
empty_command_request!(ProtocolAvailable, "protocol available");
|
||||
|
||||
impl Command for ProtocolAvailable {
|
||||
type Request = ();
|
||||
multi_item_command_response!(ProtocolAvailable, "feature", String);
|
||||
|
||||
impl Command<'_, '_> for ProtocolAvailable {
|
||||
type Request = ProtocolAvailableRequest;
|
||||
type Response = ProtocolAvailableResponse;
|
||||
const COMMAND: &'static str = "protocol available";
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
|
||||
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<'_>> {
|
||||
let parts_: Vec<_> = parts.into_vec()?;
|
||||
if let Some((k, _)) = parts_.iter().find(|(k, _)| *k != "feature") {
|
||||
return Err(ResponseParserError::UnexpectedProperty(k));
|
||||
}
|
||||
|
||||
let list = parts_
|
||||
.into_iter()
|
||||
.map(|(k, v)| Ok(expect_property_type!(Some(v), k, Text).to_string()))
|
||||
.collect::<Result<Vec<_>, ResponseParserError>>()?;
|
||||
|
||||
Ok(list)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct ProtocolClear;
|
||||
|
||||
impl Command for ProtocolClear {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "protocol clear";
|
||||
empty_command_request!(ProtocolClear, "protocol clear");
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
empty_command_response!(ProtocolClear);
|
||||
|
||||
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 ProtocolClear {
|
||||
type Request = ProtocolClearRequest;
|
||||
type Response = ProtocolClearResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
common::types::Feature,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,32 +9,53 @@ use crate::{
|
||||
|
||||
pub struct ProtocolDisable;
|
||||
|
||||
pub type ProtocolDisableRequest = Vec<Feature>;
|
||||
pub struct ProtocolDisableRequest(Vec<Feature>);
|
||||
|
||||
impl Command for ProtocolDisable {
|
||||
type Request = ProtocolDisableRequest;
|
||||
type Response = ();
|
||||
impl CommandRequest<'_> for ProtocolDisableRequest {
|
||||
const COMMAND: &'static str = "protocol disable";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request.join(" "))
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::ProtocolDisable(self.0)
|
||||
}
|
||||
|
||||
fn parse_request(parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::ProtocolDisable(features) => Some(ProtocolDisableRequest(features)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
let features = self
|
||||
.0
|
||||
.iter()
|
||||
.map(|f| f.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(" ");
|
||||
format!("{} {}", Self::COMMAND, features)
|
||||
}
|
||||
|
||||
fn parse(parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let mut parts = parts.peekable();
|
||||
if parts.peek().is_none() {
|
||||
return Err(RequestParserError::UnexpectedEOF);
|
||||
}
|
||||
|
||||
let features = parts.map(|s| s.to_string()).collect::<Vec<String>>();
|
||||
let mut features = Vec::new();
|
||||
for part in parts {
|
||||
let feature = part
|
||||
.parse()
|
||||
.map_err(|_| RequestParserError::SyntaxError(1, part.to_owned()))?;
|
||||
features.push(feature);
|
||||
}
|
||||
|
||||
Ok(features)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
Ok(ProtocolDisableRequest(features))
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(ProtocolDisable);
|
||||
|
||||
impl Command<'_, '_> for ProtocolDisable {
|
||||
type Request = ProtocolDisableRequest;
|
||||
type Response = ProtocolDisableResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
common::types::Feature,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,32 +9,53 @@ use crate::{
|
||||
|
||||
pub struct ProtocolEnable;
|
||||
|
||||
pub type ProtocolEnableRequest = Vec<Feature>;
|
||||
pub struct ProtocolEnableRequest(Vec<Feature>);
|
||||
|
||||
impl Command for ProtocolEnable {
|
||||
type Request = ProtocolEnableRequest;
|
||||
type Response = ();
|
||||
impl CommandRequest<'_> for ProtocolEnableRequest {
|
||||
const COMMAND: &'static str = "protocol enable";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request.join(" "))
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::ProtocolEnable(self.0)
|
||||
}
|
||||
|
||||
fn parse_request(parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::ProtocolEnable(features) => Some(ProtocolEnableRequest(features)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
let features = self
|
||||
.0
|
||||
.iter()
|
||||
.map(|f| f.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(" ");
|
||||
format!("{} {}", Self::COMMAND, features)
|
||||
}
|
||||
|
||||
fn parse(parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let mut parts = parts.peekable();
|
||||
if parts.peek().is_none() {
|
||||
return Err(RequestParserError::UnexpectedEOF);
|
||||
}
|
||||
|
||||
let features = parts.map(|s| s.to_string()).collect::<Vec<String>>();
|
||||
let mut features = Vec::new();
|
||||
for part in parts {
|
||||
let feature = part
|
||||
.parse()
|
||||
.map_err(|_| RequestParserError::SyntaxError(1, part.to_owned()))?;
|
||||
features.push(feature);
|
||||
}
|
||||
|
||||
Ok(features)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
Ok(ProtocolEnableRequest(features))
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(ProtocolEnable);
|
||||
|
||||
impl Command<'_, '_> for ProtocolEnable {
|
||||
type Request = ProtocolEnableRequest;
|
||||
type Response = ProtocolEnableResponse;
|
||||
}
|
||||
|
||||
@@ -1,43 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
multi_item_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{ResponseAttributes, expect_property_type},
|
||||
};
|
||||
|
||||
pub struct TagTypes;
|
||||
|
||||
pub type TagTypesResponse = Vec<String>;
|
||||
empty_command_request!(TagTypes, "tagtypes");
|
||||
|
||||
impl Command for TagTypes {
|
||||
type Request = ();
|
||||
multi_item_command_response!(TagTypes, "tagtype", String);
|
||||
|
||||
impl Command<'_, '_> for TagTypes {
|
||||
type Request = TagTypesRequest;
|
||||
type Response = TagTypesResponse;
|
||||
const COMMAND: &'static str = "tagtypes";
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
|
||||
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<'_>> {
|
||||
let parts: Vec<_> = parts.into_vec()?;
|
||||
|
||||
let mut tagtypes = Vec::with_capacity(parts.len());
|
||||
for (key, value) in parts.into_iter() {
|
||||
if key != "tagtype" {
|
||||
return Err(ResponseParserError::UnexpectedProperty(key));
|
||||
}
|
||||
|
||||
let tagtype = expect_property_type!(Some(value), "tagtype", Text).to_string();
|
||||
|
||||
tagtypes.push(tagtype);
|
||||
}
|
||||
|
||||
Ok(tagtypes)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct TagTypesAll;
|
||||
|
||||
impl Command for TagTypesAll {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "tagtypes all";
|
||||
empty_command_request!(TagTypesAll, "tagtypes all");
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
empty_command_response!(TagTypesAll);
|
||||
|
||||
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 TagTypesAll {
|
||||
type Request = TagTypesAllRequest;
|
||||
type Response = TagTypesAllResponse;
|
||||
}
|
||||
|
||||
@@ -1,43 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
multi_item_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{ResponseAttributes, expect_property_type},
|
||||
};
|
||||
|
||||
pub struct TagTypesAvailable;
|
||||
|
||||
pub type TagTypesAvailableResponse = Vec<String>;
|
||||
empty_command_request!(TagTypesAvailable, "tagtypes available");
|
||||
|
||||
impl Command for TagTypesAvailable {
|
||||
type Request = ();
|
||||
multi_item_command_response!(TagTypesAvailable, "tagtype", String);
|
||||
|
||||
impl Command<'_, '_> for TagTypesAvailable {
|
||||
type Request = TagTypesAvailableRequest;
|
||||
type Response = TagTypesAvailableResponse;
|
||||
const COMMAND: &'static str = "tagtypes available";
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
|
||||
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<'_>> {
|
||||
let parts: Vec<_> = parts.into_vec()?;
|
||||
|
||||
let mut tagtypes = Vec::with_capacity(parts.len());
|
||||
for (key, value) in parts.into_iter() {
|
||||
if key != "tagtype" {
|
||||
return Err(ResponseParserError::UnexpectedProperty(key));
|
||||
}
|
||||
|
||||
let tagtype = expect_property_type!(Some(value), "tagtype", Text).to_string();
|
||||
|
||||
tagtypes.push(tagtype);
|
||||
}
|
||||
|
||||
Ok(tagtypes)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct TagTypesClear;
|
||||
|
||||
impl Command for TagTypesClear {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "tagtypes clear";
|
||||
empty_command_request!(TagTypesClear, "tagtypes clear");
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
empty_command_response!(TagTypesClear);
|
||||
|
||||
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 TagTypesClear {
|
||||
type Request = TagTypesClearRequest;
|
||||
type Response = TagTypesClearResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
common::types::TagName,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,32 +9,54 @@ use crate::{
|
||||
|
||||
pub struct TagTypesDisable;
|
||||
|
||||
pub type TagTypesDisableRequest = Vec<TagName>;
|
||||
pub struct TagTypesDisableRequest(Vec<TagName>);
|
||||
|
||||
impl Command for TagTypesDisable {
|
||||
type Request = TagTypesDisableRequest;
|
||||
type Response = ();
|
||||
impl CommandRequest<'_> for TagTypesDisableRequest {
|
||||
const COMMAND: &'static str = "tagtypes disable";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request.join(" "))
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::TagTypesDisable(self.0)
|
||||
}
|
||||
|
||||
fn parse_request(parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::TagTypesDisable(req) => Some(TagTypesDisableRequest(req)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
format!(
|
||||
"{} {}",
|
||||
Self::COMMAND,
|
||||
self.0
|
||||
.iter()
|
||||
.map(|tag| tag.as_str())
|
||||
.collect::<Vec<&str>>()
|
||||
.join(" ")
|
||||
)
|
||||
}
|
||||
|
||||
fn parse(parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let mut parts = parts.peekable();
|
||||
if parts.peek().is_none() {
|
||||
return Err(RequestParserError::UnexpectedEOF);
|
||||
}
|
||||
|
||||
let tag_types = parts.map(|s| s.to_string()).collect::<Vec<String>>();
|
||||
let tag_types = parts
|
||||
.map(|s| {
|
||||
s.parse()
|
||||
.map_err(|_| RequestParserError::SyntaxError(1, s.to_owned()))
|
||||
})
|
||||
.collect::<Result<Vec<TagName>, RequestParserError>>()?;
|
||||
|
||||
Ok(tag_types)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
Ok(TagTypesDisableRequest(tag_types))
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(TagTypesDisable);
|
||||
|
||||
impl Command<'_, '_> for TagTypesDisable {
|
||||
type Request = TagTypesDisableRequest;
|
||||
type Response = TagTypesDisableResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
common::types::TagName,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,32 +9,54 @@ use crate::{
|
||||
|
||||
pub struct TagTypesEnable;
|
||||
|
||||
pub type TagTypesEnableRequest = Vec<TagName>;
|
||||
pub struct TagTypesEnableRequest(Vec<TagName>);
|
||||
|
||||
impl Command for TagTypesEnable {
|
||||
type Request = TagTypesEnableRequest;
|
||||
type Response = ();
|
||||
impl CommandRequest<'_> for TagTypesEnableRequest {
|
||||
const COMMAND: &'static str = "tagtypes enable";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request.join(" "))
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::TagTypesEnable(self.0)
|
||||
}
|
||||
|
||||
fn parse_request(parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::TagTypesEnable(req) => Some(TagTypesEnableRequest(req)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
format!(
|
||||
"{} {}",
|
||||
Self::COMMAND,
|
||||
self.0
|
||||
.iter()
|
||||
.map(|tag| tag.as_str())
|
||||
.collect::<Vec<&str>>()
|
||||
.join(" ")
|
||||
)
|
||||
}
|
||||
|
||||
fn parse(parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let mut parts = parts.peekable();
|
||||
if parts.peek().is_none() {
|
||||
return Err(RequestParserError::UnexpectedEOF);
|
||||
}
|
||||
|
||||
let tag_types = parts.map(|s| s.to_string()).collect::<Vec<String>>();
|
||||
let tag_types = parts
|
||||
.map(|s| {
|
||||
s.parse()
|
||||
.map_err(|_| RequestParserError::SyntaxError(1, s.to_owned()))
|
||||
})
|
||||
.collect::<Result<Vec<TagName>, RequestParserError>>()?;
|
||||
|
||||
Ok(tag_types)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
Ok(TagTypesEnableRequest(tag_types))
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(TagTypesEnable);
|
||||
|
||||
impl Command<'_, '_> for TagTypesEnable {
|
||||
type Request = TagTypesEnableRequest;
|
||||
type Response = TagTypesEnableResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
common::types::TagName,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,33 +9,54 @@ use crate::{
|
||||
|
||||
pub struct TagTypesReset;
|
||||
|
||||
pub type TagTypesResetRequest = Vec<TagName>;
|
||||
pub struct TagTypesResetRequest(Vec<TagName>);
|
||||
|
||||
impl Command for TagTypesReset {
|
||||
type Request = TagTypesResetRequest;
|
||||
type Response = ();
|
||||
impl CommandRequest<'_> for TagTypesResetRequest {
|
||||
const COMMAND: &'static str = "tagtypes reset";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request.join(" "))
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::TagTypesReset(self.0)
|
||||
}
|
||||
|
||||
fn parse_request(parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::TagTypesReset(req) => Some(TagTypesResetRequest(req)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
format!(
|
||||
"{} {}",
|
||||
Self::COMMAND,
|
||||
self.0
|
||||
.iter()
|
||||
.map(|tag| tag.as_str())
|
||||
.collect::<Vec<&str>>()
|
||||
.join(" ")
|
||||
)
|
||||
}
|
||||
|
||||
fn parse(parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let mut parts = parts.peekable();
|
||||
if parts.peek().is_none() {
|
||||
return Err(RequestParserError::UnexpectedEOF);
|
||||
}
|
||||
|
||||
// TODO: verify that the tag types are split by whitespace
|
||||
let tag_types = parts.map(|s| s.to_string()).collect::<Vec<String>>();
|
||||
let tag_types = parts
|
||||
.map(|s| {
|
||||
s.parse()
|
||||
.map_err(|_| RequestParserError::SyntaxError(1, s.to_owned()))
|
||||
})
|
||||
.collect::<Result<Vec<TagName>, RequestParserError>>()?;
|
||||
|
||||
Ok(tag_types)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
Ok(TagTypesResetRequest(tag_types))
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(TagTypesReset);
|
||||
|
||||
impl Command<'_, '_> for TagTypesReset {
|
||||
type Request = TagTypesResetRequest;
|
||||
type Response = TagTypesResetResponse;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct Next;
|
||||
|
||||
impl Command for Next {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "next";
|
||||
empty_command_request!(Next, "next");
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
empty_command_response!(Next);
|
||||
|
||||
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 Next {
|
||||
type Request = NextRequest;
|
||||
type Response = NextResponse;
|
||||
}
|
||||
|
||||
@@ -1,25 +1,38 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct Pause;
|
||||
|
||||
impl Command for Pause {
|
||||
type Request = Option<bool>;
|
||||
type Response = ();
|
||||
pub struct PauseRequest(Option<bool>);
|
||||
|
||||
impl CommandRequest<'_> for PauseRequest {
|
||||
const COMMAND: &'static str = "pause";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::Pause(self.0)
|
||||
}
|
||||
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::Pause(value) => Some(PauseRequest(value)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
match self.0 {
|
||||
Some(true) => format!("{} 1", Self::COMMAND),
|
||||
Some(false) => format!("{} 0", Self::COMMAND),
|
||||
None => Self::COMMAND.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let result = match parts.next() {
|
||||
Some("0") => Ok(Some(false)),
|
||||
Some("1") => Ok(Some(true)),
|
||||
@@ -29,13 +42,13 @@ impl Command for Pause {
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
result.map(PauseRequest)
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(Pause);
|
||||
|
||||
impl Command<'_, '_> for Pause {
|
||||
type Request = PauseRequest;
|
||||
type Response = PauseResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::SongPosition,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,32 +10,11 @@ use crate::{
|
||||
|
||||
pub struct Play;
|
||||
|
||||
impl Command for Play {
|
||||
type Request = SongPosition;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "play";
|
||||
single_item_command_request!(Play, "play", SongPosition);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(Play);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let songpos = match parts.next() {
|
||||
Some(s) => s
|
||||
.parse::<SongPosition>()
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, s.to_owned()))?,
|
||||
None => return Err(RequestParserError::UnexpectedEOF),
|
||||
};
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(songpos)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for Play {
|
||||
type Request = PlayRequest;
|
||||
type Response = PlayResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response, single_item_command_request,
|
||||
},
|
||||
common::types::SongId,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,32 +10,11 @@ use crate::{
|
||||
|
||||
pub struct PlayId;
|
||||
|
||||
impl Command for PlayId {
|
||||
type Request = SongId;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "playid";
|
||||
single_item_command_request!(PlayId, "playid", SongId);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(PlayId);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let songid = match parts.next() {
|
||||
Some(s) => s
|
||||
.parse::<SongId>()
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, s.to_owned()))?,
|
||||
None => return Err(RequestParserError::UnexpectedEOF),
|
||||
};
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(songid)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for PlayId {
|
||||
type Request = PlayIdRequest;
|
||||
type Response = PlayIdResponse;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct Previous;
|
||||
|
||||
impl Command for Previous {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "previous";
|
||||
empty_command_request!(Previous, "previous");
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
empty_command_response!(Previous);
|
||||
|
||||
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 Previous {
|
||||
type Request = PreviousRequest;
|
||||
type Response = PreviousResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
common::types::{SongPosition, TimeWithFractions},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -15,16 +17,25 @@ pub struct SeekRequest {
|
||||
pub time: TimeWithFractions,
|
||||
}
|
||||
|
||||
impl Command for Seek {
|
||||
type Request = SeekRequest;
|
||||
type Response = ();
|
||||
impl CommandRequest<'_> for SeekRequest {
|
||||
const COMMAND: &'static str = "seek";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {} {}", Self::COMMAND, request.songpos, request.time)
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::Seek(self.songpos, self.time)
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::Seek(songpos, time) => Some(SeekRequest { songpos, time }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
format!("{} {} {}", Self::COMMAND, self.songpos, self.time)
|
||||
}
|
||||
|
||||
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let songpos = match parts.next() {
|
||||
Some(s) => s
|
||||
.parse::<SongPosition>()
|
||||
@@ -43,11 +54,11 @@ impl Command for Seek {
|
||||
|
||||
Ok(SeekRequest { songpos, time })
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(Seek);
|
||||
|
||||
impl Command<'_, '_> for Seek {
|
||||
type Request = SeekRequest;
|
||||
type Response = SeekResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseAttributes, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseAttributes, ResponseParserError,
|
||||
empty_command_response,
|
||||
},
|
||||
common::types::{SeekMode, TimeWithFractions},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
};
|
||||
@@ -14,23 +17,32 @@ pub struct SeekCurRequest {
|
||||
pub time: TimeWithFractions,
|
||||
}
|
||||
|
||||
impl Command for SeekCur {
|
||||
type Request = SeekCurRequest;
|
||||
type Response = ();
|
||||
impl CommandRequest<'_> for SeekCurRequest {
|
||||
const COMMAND: &'static str = "seekcur";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
let time_str = match request.mode {
|
||||
SeekMode::Absolute => format!("{}", request.time),
|
||||
SeekMode::Relative if request.time >= 0.0 => format!("+{}", request.time),
|
||||
SeekMode::Relative => format!("-{}", -request.time),
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::SeekCur(self.mode, self.time)
|
||||
}
|
||||
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::SeekCur(mode, time) => Some(SeekCurRequest { mode, time }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
let time_str = match self.mode {
|
||||
SeekMode::Absolute => format!("{}", self.time),
|
||||
SeekMode::Relative if self.time >= 0.0 => format!("+{}", self.time),
|
||||
SeekMode::Relative => format!("-{}", -self.time),
|
||||
SeekMode::RelativeReverse => unimplemented!(), // TODO: should this happen?
|
||||
};
|
||||
|
||||
format!("{} {}", Self::COMMAND, time_str)
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let time_raw = match parts.next() {
|
||||
Some(t) => t,
|
||||
None => return Err(RequestParserError::UnexpectedEOF),
|
||||
@@ -61,11 +73,11 @@ impl Command for SeekCur {
|
||||
|
||||
Ok(SeekCurRequest { mode, time })
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(SeekCur);
|
||||
|
||||
impl Command<'_, '_> for SeekCur {
|
||||
type Request = SeekCurRequest;
|
||||
type Response = SeekCurResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
common::types::{SongId, TimeWithFractions},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -15,16 +17,25 @@ pub struct SeekIdRequest {
|
||||
pub time: TimeWithFractions,
|
||||
}
|
||||
|
||||
impl Command for SeekId {
|
||||
type Request = SeekIdRequest;
|
||||
type Response = ();
|
||||
impl CommandRequest<'_> for SeekIdRequest {
|
||||
const COMMAND: &'static str = "seekid";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {} {}", Self::COMMAND, request.songid, request.time)
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::SeekId(self.songid, self.time)
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::SeekId(songid, time) => Some(SeekIdRequest { songid, time }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
format!("{} {} {}", Self::COMMAND, self.songid, self.time)
|
||||
}
|
||||
|
||||
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let songid = match parts.next() {
|
||||
Some(s) => s
|
||||
.parse::<SongId>()
|
||||
@@ -43,11 +54,11 @@ impl Command for SeekId {
|
||||
|
||||
Ok(SeekIdRequest { songid, time })
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(SeekId);
|
||||
|
||||
impl Command<'_, '_> for SeekId {
|
||||
type Request = SeekIdRequest;
|
||||
type Response = SeekIdResponse;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct Stop;
|
||||
|
||||
impl Command for Stop {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "stop";
|
||||
empty_command_request!(Stop, "stop");
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
empty_command_response!(Stop);
|
||||
|
||||
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 Stop {
|
||||
type Request = StopRequest;
|
||||
type Response = StopResponse;
|
||||
}
|
||||
|
||||
@@ -1,39 +1,21 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
multi_item_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{ResponseAttributes, expect_property_type},
|
||||
};
|
||||
|
||||
pub struct ListMounts;
|
||||
|
||||
impl Command for ListMounts {
|
||||
type Request = ();
|
||||
type Response = Vec<String>;
|
||||
const COMMAND: &'static str = "listmounts";
|
||||
empty_command_request!(ListMounts, "listmounts");
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
multi_item_command_response!(ListMounts, "mount", String);
|
||||
|
||||
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<'_>> {
|
||||
let parts: Vec<_> = parts.into_vec()?;
|
||||
let mut result = Vec::with_capacity(parts.len());
|
||||
for (key, value) in parts.into_iter() {
|
||||
if key != "mount" {
|
||||
return Err(ResponseParserError::UnexpectedProperty(key));
|
||||
}
|
||||
let value = expect_property_type!(Some(value), "mount", Text).to_string();
|
||||
result.push(value);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
impl Command<'_, '_> for ListMounts {
|
||||
type Request = ListMountsRequest;
|
||||
type Response = ListMountsResponse;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -49,7 +31,13 @@ mod tests {
|
||||
mount: /mnt/music
|
||||
OK
|
||||
"};
|
||||
let result = ListMounts::parse_raw_response(input);
|
||||
assert_eq!(result, Ok(vec!["".to_string(), "/mnt/music".to_string(),]));
|
||||
let result = ListMounts::parse_raw_response(input.as_bytes());
|
||||
assert_eq!(
|
||||
result,
|
||||
Ok(ListMountsResponse(vec![
|
||||
"".to_string(),
|
||||
"/mnt/music".to_string(),
|
||||
]))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,29 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandResponse, RequestParserError, ResponseParserError, empty_command_request,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{ResponseAttributes, expect_property_type},
|
||||
};
|
||||
|
||||
pub struct ListNeighbors;
|
||||
|
||||
pub type ListNeighborsResponse = HashMap<String, String>;
|
||||
empty_command_request!(ListNeighbors, "listneighbors");
|
||||
|
||||
impl Command for ListNeighbors {
|
||||
type Request = ();
|
||||
type Response = ListNeighborsResponse;
|
||||
const COMMAND: &'static str = "listneighbors";
|
||||
pub struct ListNeighborsResponse(HashMap<String, String>);
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
impl CommandResponse<'_> for ListNeighborsResponse {
|
||||
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<'_>> {
|
||||
let parts: Vec<_> = parts.into_vec()?;
|
||||
debug_assert!(parts.len() % 2 == 0);
|
||||
|
||||
@@ -45,6 +42,11 @@ impl Command for ListNeighbors {
|
||||
result.insert(neighbor, name);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
Ok(ListNeighborsResponse(result))
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<'_, '_> for ListNeighbors {
|
||||
type Request = ListNeighborsRequest;
|
||||
type Response = ListNeighborsResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response,
|
||||
},
|
||||
common::types::{MountPath, Uri},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
@@ -10,20 +14,35 @@ pub struct Mount;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MountRequest {
|
||||
pub path: String,
|
||||
pub uri: String,
|
||||
pub path: MountPath,
|
||||
pub uri: Uri,
|
||||
}
|
||||
|
||||
impl Command for Mount {
|
||||
type Request = MountRequest;
|
||||
type Response = ();
|
||||
impl CommandRequest<'_> for MountRequest {
|
||||
const COMMAND: &'static str = "mount";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {} {}", Self::COMMAND, request.path, request.uri)
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::Mount(self.path, self.uri)
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::Mount(path, uri) => Some(MountRequest { path, uri }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
debug_assert!(!self.path.to_str().is_none());
|
||||
format!(
|
||||
"{} {} {}",
|
||||
Self::COMMAND,
|
||||
self.path.to_str().unwrap_or("<invalid path>"),
|
||||
self.uri
|
||||
)
|
||||
}
|
||||
|
||||
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let path = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
let path = path
|
||||
.parse()
|
||||
@@ -38,11 +57,11 @@ impl Command for Mount {
|
||||
|
||||
Ok(MountRequest { path, uri })
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(Mount);
|
||||
|
||||
impl Command<'_, '_> for Mount {
|
||||
type Request = MountRequest;
|
||||
type Response = MountResponse;
|
||||
}
|
||||
|
||||
@@ -1,37 +1,60 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
MountPath,
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, RequestTokenizer, ResponseParserError,
|
||||
empty_command_response, single_item_command_request,
|
||||
},
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct Unmount;
|
||||
|
||||
pub type UnmountRequest = String;
|
||||
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct UnmountRequest(MountPath);
|
||||
|
||||
impl Command for Unmount {
|
||||
type Request = UnmountRequest;
|
||||
type Response = ();
|
||||
impl CommandRequest<'_> for UnmountRequest {
|
||||
const COMMAND: &'static str = "unmount";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
match Self::COMMAND {
|
||||
"unmount" => crate::Request::Unmount(self.0),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let path = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
let path = path
|
||||
.parse()
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, path.to_string()))?;
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match (Self::COMMAND, request) {
|
||||
("unmount", crate::Request::Unmount(item)) => Some(UnmountRequest(item)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
debug_assert!(!self.0.to_str().is_none());
|
||||
format!(
|
||||
"{} {}",
|
||||
Self::COMMAND,
|
||||
self.0.to_str().unwrap_or("<invalid path>")
|
||||
)
|
||||
}
|
||||
|
||||
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let item_token = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
let item = item_token
|
||||
.parse::<MountPath>()
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, item_token.to_owned()))?;
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
Ok(UnmountRequest(item))
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(Unmount);
|
||||
|
||||
impl Command<'_, '_> for Unmount {
|
||||
type Request = UnmountRequest;
|
||||
type Response = UnmountResponse;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError},
|
||||
common::types::{Offset, Uri},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{ResponseAttributes, get_and_parse_property, get_property},
|
||||
@@ -17,22 +17,25 @@ pub struct AlbumArtRequest {
|
||||
offset: Offset,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct AlbumArtResponse {
|
||||
pub size: usize,
|
||||
pub binary: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Command for AlbumArt {
|
||||
type Request = AlbumArtRequest;
|
||||
type Response = AlbumArtResponse;
|
||||
impl CommandRequest<'_> for AlbumArtRequest {
|
||||
const COMMAND: &'static str = "albumart";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {} {}", Self::COMMAND, request.uri, request.offset)
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::AlbumArt(self.uri, self.offset)
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::AlbumArt(uri, offset) => Some(AlbumArtRequest { uri, offset }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
format!("{} {} {}", Self::COMMAND, self.uri, self.offset)
|
||||
}
|
||||
|
||||
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let uri = match parts.next() {
|
||||
Some(s) => s,
|
||||
None => return Err(RequestParserError::UnexpectedEOF),
|
||||
@@ -52,10 +55,24 @@ impl Command for AlbumArt {
|
||||
offset,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct AlbumArtResponse {
|
||||
pub size: usize,
|
||||
pub binary: Vec<u8>,
|
||||
}
|
||||
|
||||
impl CommandResponse<'_> for AlbumArtResponse {
|
||||
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: HashMap<_, _> = parts.into_map()?;
|
||||
|
||||
let size = get_and_parse_property!(parts, "size", Text);
|
||||
@@ -65,3 +82,8 @@ impl Command for AlbumArt {
|
||||
Ok(AlbumArtResponse { size, binary })
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<'_, '_> for AlbumArt {
|
||||
type Request = AlbumArtRequest;
|
||||
type Response = AlbumArtResponse;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError},
|
||||
common::types::GroupType,
|
||||
filter::Filter,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
@@ -18,26 +18,29 @@ pub struct CountRequest {
|
||||
group: Option<GroupType>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct CountResponse {
|
||||
pub songs: usize,
|
||||
pub playtime: u64,
|
||||
}
|
||||
|
||||
impl Command for Count {
|
||||
type Request = CountRequest;
|
||||
type Response = CountResponse;
|
||||
impl CommandRequest<'_> for CountRequest {
|
||||
const COMMAND: &'static str = "count";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
let mut cmd = format!("{} {}", Self::COMMAND, request.filter);
|
||||
if let Some(group) = request.group {
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::Count(self.filter, self.group)
|
||||
}
|
||||
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::Count(filter, group) => Some(CountRequest { filter, group }),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
let mut cmd = format!("{} {}", Self::COMMAND, self.filter);
|
||||
if let Some(group) = self.group.as_ref() {
|
||||
cmd.push_str(&format!(" group {}", group));
|
||||
}
|
||||
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()))?
|
||||
@@ -61,10 +64,24 @@ impl Command for Count {
|
||||
|
||||
Ok(CountRequest { filter, group })
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct CountResponse {
|
||||
pub songs: usize,
|
||||
pub playtime: u64,
|
||||
}
|
||||
|
||||
impl CommandResponse<'_> for CountResponse {
|
||||
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: HashMap<_, _> = parts.into_map()?;
|
||||
|
||||
let songs = get_and_parse_property!(parts, "songs", Text);
|
||||
@@ -73,3 +90,8 @@ impl Command for Count {
|
||||
Ok(CountResponse { songs, playtime })
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<'_, '_> for Count {
|
||||
type Request = CountRequest;
|
||||
type Response = CountResponse;
|
||||
}
|
||||
|
||||
@@ -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,26 +17,36 @@ pub struct FindRequest {
|
||||
window: Option<WindowRange>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct FindResponse {}
|
||||
|
||||
impl Command for Find {
|
||||
type Request = FindRequest;
|
||||
type Response = FindResponse;
|
||||
impl CommandRequest<'_> for FindRequest {
|
||||
const COMMAND: &'static str = "find";
|
||||
|
||||
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::Find(self.filter, self.sort, self.window)
|
||||
}
|
||||
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::Find(filter, sort, window) => Some(FindRequest {
|
||||
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()))?
|
||||
@@ -72,10 +82,26 @@ impl Command for Find {
|
||||
window,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct FindResponse {}
|
||||
|
||||
impl CommandResponse<'_> for FindResponse {
|
||||
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<'_>> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<'_, '_> for Find {
|
||||
type Request = FindRequest;
|
||||
type Response = FindResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
common::types::{SongPosition, Sort, WindowRange},
|
||||
filter::Filter,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
@@ -18,26 +20,40 @@ pub struct FindAddRequest {
|
||||
position: Option<SongPosition>,
|
||||
}
|
||||
|
||||
impl Command for FindAdd {
|
||||
type Request = FindAddRequest;
|
||||
type Response = ();
|
||||
impl CommandRequest<'_> for FindAddRequest {
|
||||
const COMMAND: &'static str = "findadd";
|
||||
|
||||
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::FindAdd(self.filter, self.sort, self.window, self.position)
|
||||
}
|
||||
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::FindAdd(filter, sort, window, position) => Some(FindAddRequest {
|
||||
filter,
|
||||
sort,
|
||||
window,
|
||||
position,
|
||||
}),
|
||||
_ => 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));
|
||||
}
|
||||
if let Some(position) = request.position {
|
||||
if let Some(position) = &self.position {
|
||||
cmd.push_str(&format!(" position {}", position));
|
||||
}
|
||||
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()))?
|
||||
@@ -84,11 +100,11 @@ impl Command for FindAdd {
|
||||
position,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(FindAdd);
|
||||
|
||||
impl Command<'_, '_> for FindAdd {
|
||||
type Request = FindAddRequest;
|
||||
type Response = FindAddResponse;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@ use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandResponse, RequestParserError, ResponseParserError,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::Uri,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{ResponseAttributes, get_and_parse_property},
|
||||
@@ -11,34 +14,23 @@ use crate::{
|
||||
|
||||
pub struct GetFingerprint;
|
||||
|
||||
single_item_command_request!(GetFingerprint, "getfingerprint", Uri);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct GetFingerprintResponse {
|
||||
pub chromaprint: String,
|
||||
}
|
||||
|
||||
impl Command for GetFingerprint {
|
||||
type Request = Uri;
|
||||
type Response = GetFingerprintResponse;
|
||||
const COMMAND: &'static str = "getfingerprint";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
impl CommandResponse<'_> for GetFingerprintResponse {
|
||||
fn into_response_enum(self) -> crate::Response {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let uri = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
let uri = uri
|
||||
.parse()
|
||||
.map_err(|_| RequestParserError::SyntaxError(1, uri.to_owned()))?;
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(uri)
|
||||
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<'_>> {
|
||||
let parts: HashMap<_, _> = parts.into_map()?;
|
||||
|
||||
let chromaprint = get_and_parse_property!(parts, "chromaprint", Text);
|
||||
@@ -46,3 +38,8 @@ impl Command for GetFingerprint {
|
||||
Ok(GetFingerprintResponse { chromaprint })
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<'_, '_> for GetFingerprint {
|
||||
type Request = GetFingerprintRequest;
|
||||
type Response = GetFingerprintResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, CommandResponse, RequestParserError, ResponseParserError,
|
||||
multi_item_command_response,
|
||||
},
|
||||
common::types::{GroupType, TagName, WindowRange},
|
||||
filter::Filter,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
@@ -18,28 +21,40 @@ pub struct ListRequest {
|
||||
window: Option<WindowRange>,
|
||||
}
|
||||
|
||||
pub type ListResponse = Vec<String>;
|
||||
|
||||
impl Command for List {
|
||||
type Request = ListRequest;
|
||||
type Response = ListResponse;
|
||||
impl CommandRequest<'_> for ListRequest {
|
||||
const COMMAND: &'static str = "list";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
let mut cmd = match &request.filter {
|
||||
Some(f) => format!("{} {} {}", Self::COMMAND, request.tagname, f),
|
||||
None => format!("{} {}", Self::COMMAND, request.tagname),
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::List(self.tagname, self.filter, self.groups, self.window)
|
||||
}
|
||||
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::List(tagname, filter, groups, window) => Some(ListRequest {
|
||||
tagname,
|
||||
filter,
|
||||
groups,
|
||||
window,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
let mut cmd = match &self.filter {
|
||||
Some(f) => format!("{} {} {}", Self::COMMAND, self.tagname, f),
|
||||
None => format!("{} {}", Self::COMMAND, self.tagname),
|
||||
};
|
||||
for group in request.groups {
|
||||
for group in &self.groups {
|
||||
cmd.push_str(&format!(" group {}", group));
|
||||
}
|
||||
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 tagname = parts.next().ok_or(RequestParserError::UnexpectedEOF)?;
|
||||
let tagname = tagname
|
||||
.parse()
|
||||
@@ -91,10 +106,20 @@ impl Command for List {
|
||||
window,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
pub struct ListResponse(Vec<String>);
|
||||
|
||||
impl CommandResponse<'_> for ListResponse {
|
||||
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_vec()?;
|
||||
debug_assert!({
|
||||
let key = parts_.first().map(|(k, _)| k);
|
||||
@@ -106,6 +131,11 @@ impl Command for List {
|
||||
.map(|(k, v)| Ok(expect_property_type!(Some(v), k, Text).to_string()))
|
||||
.collect::<Result<Vec<_>, ResponseParserError>>()?;
|
||||
|
||||
Ok(list)
|
||||
Ok(ListResponse(list))
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<'_, '_> for List {
|
||||
type Request = ListRequest;
|
||||
type Response = ListResponse;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ pub struct ListAll;
|
||||
// TODO: This is supposed to be a tree-like structure, with directories containing files and playlists
|
||||
pub type ListAllResponse = Vec<String>;
|
||||
|
||||
impl Command for ListAll {
|
||||
impl Command<'_, '_> for ListAll {
|
||||
type Request = Option<Uri>;
|
||||
type Response = ListAllResponse;
|
||||
const COMMAND: &'static str = "listall";
|
||||
|
||||
@@ -11,7 +11,7 @@ pub struct ListAllInfo;
|
||||
// in addition to the metadata of each entry
|
||||
pub type ListAllInfoResponse = Vec<String>;
|
||||
|
||||
impl Command for ListAllInfo {
|
||||
impl Command<'_, '_> for ListAllInfo {
|
||||
type Request = Option<Uri>;
|
||||
type Response = ListAllInfoResponse;
|
||||
const COMMAND: &'static str = "listallinfo";
|
||||
|
||||
@@ -10,7 +10,7 @@ pub struct ListFiles;
|
||||
// TODO: fix this type
|
||||
pub type ListFilesResponse = Vec<String>;
|
||||
|
||||
impl Command for ListFiles {
|
||||
impl Command<'_, '_> for ListFiles {
|
||||
type Request = Option<Uri>;
|
||||
type Response = ListFilesResponse;
|
||||
const COMMAND: &'static str = "listfiles";
|
||||
|
||||
@@ -17,7 +17,7 @@ pub struct LsInfoResponseEntry {
|
||||
last_modified: Option<String>,
|
||||
}
|
||||
|
||||
impl Command for LsInfo {
|
||||
impl Command<'_, '_> for LsInfo {
|
||||
type Request = Option<Uri>;
|
||||
type Response = LsInfoResponse;
|
||||
const COMMAND: &'static str = "lsinfo";
|
||||
|
||||
@@ -11,7 +11,7 @@ pub struct ReadComments;
|
||||
|
||||
pub type ReadCommentsResponse = HashMap<String, String>;
|
||||
|
||||
impl Command for ReadComments {
|
||||
impl Command<'_, '_> for ReadComments {
|
||||
type Request = Uri;
|
||||
type Response = ReadCommentsResponse;
|
||||
const COMMAND: &'static str = "readcomments";
|
||||
|
||||
@@ -26,7 +26,7 @@ pub struct ReadPictureResponse {
|
||||
pub mimetype: Option<String>,
|
||||
}
|
||||
|
||||
impl Command for ReadPicture {
|
||||
impl Command<'_, '_> for ReadPicture {
|
||||
type Request = ReadPictureRequest;
|
||||
type Response = Option<ReadPictureResponse>;
|
||||
const COMMAND: &'static str = "readpicture";
|
||||
|
||||
@@ -16,7 +16,7 @@ pub struct RescanResponse {
|
||||
pub updating_db: usize,
|
||||
}
|
||||
|
||||
impl Command for Rescan {
|
||||
impl Command<'_, '_> for Rescan {
|
||||
type Request = Option<Uri>;
|
||||
type Response = RescanResponse;
|
||||
const COMMAND: &'static str = "rescan";
|
||||
|
||||
@@ -20,7 +20,7 @@ pub struct SearchRequest {
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SearchResponse {}
|
||||
|
||||
impl Command for Search {
|
||||
impl Command<'_, '_> for Search {
|
||||
type Request = SearchRequest;
|
||||
type Response = SearchResponse;
|
||||
const COMMAND: &'static str = "search";
|
||||
|
||||
@@ -17,7 +17,7 @@ pub struct SearchAddRequest {
|
||||
position: Option<SongPosition>,
|
||||
}
|
||||
|
||||
impl Command for SearchAdd {
|
||||
impl Command<'_, '_> for SearchAdd {
|
||||
type Request = SearchAddRequest;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "searchadd";
|
||||
|
||||
@@ -18,7 +18,7 @@ pub struct SearchAddPlRequest {
|
||||
position: Option<SongPosition>,
|
||||
}
|
||||
|
||||
impl Command for SearchAddPl {
|
||||
impl Command<'_, '_> for SearchAddPl {
|
||||
type Request = SearchAddPlRequest;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "searchaddpl";
|
||||
|
||||
@@ -24,7 +24,7 @@ pub struct SearchCountResponse {
|
||||
pub playtime: u64,
|
||||
}
|
||||
|
||||
impl Command for SearchCount {
|
||||
impl Command<'_, '_> for SearchCount {
|
||||
type Request = SearchCountRequest;
|
||||
type Response = SearchCountResponse;
|
||||
const COMMAND: &'static str = "searchcount";
|
||||
|
||||
@@ -16,7 +16,7 @@ pub struct UpdateResponse {
|
||||
updating_db: usize,
|
||||
}
|
||||
|
||||
impl Command for Update {
|
||||
impl Command<'_, '_> for Update {
|
||||
type Request = Option<Uri>;
|
||||
type Response = UpdateResponse;
|
||||
const COMMAND: &'static str = "update";
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::PartitionName,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,30 +10,11 @@ use crate::{
|
||||
|
||||
pub struct DelPartition;
|
||||
|
||||
impl Command for DelPartition {
|
||||
type Request = PartitionName;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "delpartition";
|
||||
single_item_command_request!(DelPartition, "delpartition", PartitionName);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(DelPartition);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let partition = parts
|
||||
.next()
|
||||
.ok_or(RequestParserError::UnexpectedEOF)?
|
||||
.to_string();
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(partition)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for DelPartition {
|
||||
type Request = DelPartitionRequest;
|
||||
type Response = DelPartitionResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
multi_item_command_response, single_item_command_request,
|
||||
},
|
||||
common::types::PartitionName,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{ResponseAttributes, expect_property_type},
|
||||
@@ -7,36 +10,11 @@ use crate::{
|
||||
|
||||
pub struct ListPartitions;
|
||||
|
||||
pub type ListPartitionsResponse = Vec<PartitionName>;
|
||||
empty_command_request!(ListPartitions, "listpartitions");
|
||||
|
||||
impl Command for ListPartitions {
|
||||
type Request = ();
|
||||
multi_item_command_response!(ListPartitions, "partition", PartitionName);
|
||||
|
||||
impl Command<'_, '_> for ListPartitions {
|
||||
type Request = ListPartitionsRequest;
|
||||
type Response = ListPartitionsResponse;
|
||||
const COMMAND: &'static str = "listpartitions";
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
|
||||
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<'_>> {
|
||||
let parts: Vec<_> = parts.into_vec()?;
|
||||
|
||||
let mut partitions = Vec::with_capacity(parts.len());
|
||||
for (key, value) in parts.into_iter() {
|
||||
if key != "partition" {
|
||||
return Err(ResponseParserError::UnexpectedProperty(key));
|
||||
}
|
||||
let partition = expect_property_type!(Some(value), "partition", Text).to_string();
|
||||
partitions.push(partition);
|
||||
}
|
||||
|
||||
Ok(partitions)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct MoveOutput;
|
||||
|
||||
impl Command for MoveOutput {
|
||||
type Request = String;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "moveoutput";
|
||||
single_item_command_request!(MoveOutput, "moveoutput", String);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(MoveOutput);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let output_name = parts
|
||||
.next()
|
||||
.ok_or(RequestParserError::UnexpectedEOF)?
|
||||
.to_string();
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(output_name)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for MoveOutput {
|
||||
type Request = MoveOutputRequest;
|
||||
type Response = MoveOutputResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response, single_item_command_request,
|
||||
},
|
||||
common::types::PartitionName,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,30 +10,11 @@ use crate::{
|
||||
|
||||
pub struct NewPartition;
|
||||
|
||||
impl Command for NewPartition {
|
||||
type Request = PartitionName;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "newpartition";
|
||||
single_item_command_request!(NewPartition, "newpartition", PartitionName);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(NewPartition);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let partition = parts
|
||||
.next()
|
||||
.ok_or(RequestParserError::UnexpectedEOF)?
|
||||
.to_string();
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(partition)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for NewPartition {
|
||||
type Request = NewPartitionRequest;
|
||||
type Response = NewPartitionResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::PartitionName,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,30 +10,11 @@ use crate::{
|
||||
|
||||
pub struct Partition;
|
||||
|
||||
impl Command for Partition {
|
||||
type Request = PartitionName;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "partition";
|
||||
single_item_command_request!(Partition, "partition", PartitionName);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(Partition);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let partition = parts
|
||||
.next()
|
||||
.ok_or(RequestParserError::UnexpectedEOF)?
|
||||
.to_string();
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(partition)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for Partition {
|
||||
type Request = PartitionRequest;
|
||||
type Response = PartitionResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::BoolOrOneshot,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -9,31 +12,11 @@ use crate::{
|
||||
|
||||
pub struct Consume;
|
||||
|
||||
impl Command for Consume {
|
||||
type Request = BoolOrOneshot;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "consume";
|
||||
single_item_command_request!(Consume, "consume", BoolOrOneshot);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(Consume);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let state = match parts.next() {
|
||||
Some(s) => crate::common::types::BoolOrOneshot::from_str(s)
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, s.to_owned()))?,
|
||||
None => return Err(RequestParserError::UnexpectedEOF),
|
||||
};
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for Consume {
|
||||
type Request = ConsumeRequest;
|
||||
type Response = ConsumeResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::Seconds,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,32 +10,11 @@ use crate::{
|
||||
|
||||
pub struct Crossfade;
|
||||
|
||||
impl Command for Crossfade {
|
||||
type Request = Seconds;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "crossfade";
|
||||
single_item_command_request!(Crossfade, "crossfade", Seconds);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(Crossfade);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let seconds = match parts.next() {
|
||||
Some(s) => s
|
||||
.parse::<Seconds>()
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, s.to_owned()))?,
|
||||
None => return Err(RequestParserError::UnexpectedEOF),
|
||||
};
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(seconds)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for Crossfade {
|
||||
type Request = CrossfadeRequest;
|
||||
type Response = CrossfadeResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
single_item_command_response,
|
||||
},
|
||||
common::types::VolumeValue,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{ResponseAttributes, get_and_parse_property},
|
||||
@@ -9,26 +12,11 @@ use crate::{
|
||||
|
||||
pub struct GetVol;
|
||||
|
||||
impl Command for GetVol {
|
||||
type Request = ();
|
||||
type Response = VolumeValue;
|
||||
const COMMAND: &'static str = "getvol";
|
||||
empty_command_request!(GetVol, "getvol");
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
single_item_command_response!(GetVol, "volume", VolumeValue);
|
||||
|
||||
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<'_>> {
|
||||
let parts: HashMap<_, _> = parts.into_map()?;
|
||||
assert_eq!(parts.len(), 1);
|
||||
let volume = get_and_parse_property!(parts, "volume", Text);
|
||||
Ok(volume)
|
||||
}
|
||||
impl Command<'_, '_> for GetVol {
|
||||
type Request = GetVolRequest;
|
||||
type Response = GetVolResponse;
|
||||
}
|
||||
|
||||
@@ -1,37 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct MixRampDb;
|
||||
|
||||
impl Command for MixRampDb {
|
||||
type Request = f32;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "mixrampdb";
|
||||
single_item_command_request!(MixRampDb, "mixrampdb", f32);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(MixRampDb);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let db = match parts.next() {
|
||||
Some(s) => s
|
||||
.parse::<f32>()
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, s.to_owned()))?,
|
||||
None => return Err(RequestParserError::UnexpectedEOF),
|
||||
};
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(db)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for MixRampDb {
|
||||
type Request = MixRampDbRequest;
|
||||
type Response = MixRampDbResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::Seconds,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,32 +10,10 @@ use crate::{
|
||||
|
||||
pub struct MixRampDelay;
|
||||
|
||||
impl Command for MixRampDelay {
|
||||
type Request = Seconds;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "mixrampdelay";
|
||||
single_item_command_request!(MixRampDelay, "mixrampdelay", Seconds);
|
||||
empty_command_response!(MixRampDelay);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let seconds = match parts.next() {
|
||||
Some(s) => s
|
||||
.parse::<Seconds>()
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, s.to_owned()))?,
|
||||
None => return Err(RequestParserError::UnexpectedEOF),
|
||||
};
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(seconds)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for MixRampDelay {
|
||||
type Request = MixRampDelayRequest;
|
||||
type Response = MixRampDelayResponse;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,35 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct Random;
|
||||
|
||||
impl Command for Random {
|
||||
type Request = bool;
|
||||
type Response = ();
|
||||
pub struct RandomRequest(bool);
|
||||
|
||||
impl CommandRequest<'_> for RandomRequest {
|
||||
const COMMAND: &'static str = "random";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
let state = if request { "1" } else { "0" };
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::Random(self.0)
|
||||
}
|
||||
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::Random(state) => Some(RandomRequest(state)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
let state = if self.0 { "1" } else { "0" };
|
||||
format!("{} {}", Self::COMMAND, state)
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let state = match parts.next() {
|
||||
Some("0") => false,
|
||||
Some("1") => true,
|
||||
@@ -26,13 +39,13 @@ impl Command for Random {
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
Ok(RandomRequest(state))
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(Random);
|
||||
|
||||
impl Command<'_, '_> for Random {
|
||||
type Request = RandomRequest;
|
||||
type Response = RandomResponse;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,35 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
pub struct Repeat;
|
||||
|
||||
impl Command for Repeat {
|
||||
type Request = bool;
|
||||
type Response = ();
|
||||
pub struct RepeatRequest(bool);
|
||||
|
||||
impl CommandRequest<'_> for RepeatRequest {
|
||||
const COMMAND: &'static str = "repeat";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
let state = if request { "1" } else { "0" };
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::Repeat(self.0)
|
||||
}
|
||||
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::Repeat(state) => Some(RepeatRequest(state)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
let state = if self.0 { "1" } else { "0" };
|
||||
format!("{} {}", Self::COMMAND, state)
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn parse(mut parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let state = match parts.next() {
|
||||
Some("0") => false,
|
||||
Some("1") => true,
|
||||
@@ -26,13 +39,13 @@ impl Command for Repeat {
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
Ok(RepeatRequest(state))
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(Repeat);
|
||||
|
||||
impl Command<'_, '_> for Repeat {
|
||||
type Request = RepeatRequest;
|
||||
type Response = RepeatResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::ReplayGainModeMode,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -9,31 +12,11 @@ use crate::{
|
||||
|
||||
pub struct ReplayGainMode;
|
||||
|
||||
impl Command for ReplayGainMode {
|
||||
type Request = ReplayGainModeMode;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "replay_gain_mode";
|
||||
single_item_command_request!(ReplayGainMode, "replay_gain_mode", ReplayGainModeMode);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(ReplayGainMode);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let mode = match parts.next() {
|
||||
Some(s) => ReplayGainModeMode::from_str(s)
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, s.to_owned()))?,
|
||||
None => return Err(RequestParserError::UnexpectedEOF),
|
||||
};
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(mode)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for ReplayGainMode {
|
||||
type Request = ReplayGainModeRequest;
|
||||
type Response = ReplayGainModeResponse;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ use std::{collections::HashMap, str::FromStr};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandResponse, RequestParserError, ResponseParserError, empty_command_request,
|
||||
},
|
||||
common::types::ReplayGainModeMode,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{ResponseAttributes, get_property},
|
||||
@@ -11,28 +13,23 @@ use crate::{
|
||||
|
||||
pub struct ReplayGainStatus;
|
||||
|
||||
empty_command_request!(ReplayGainStatus, "replay_gain_status");
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ReplayGainStatusResponse {
|
||||
pub replay_gain_mode: ReplayGainModeMode,
|
||||
}
|
||||
|
||||
impl Command for ReplayGainStatus {
|
||||
type Request = ();
|
||||
type Response = ReplayGainStatusResponse;
|
||||
const COMMAND: &'static str = "replay_gain_status";
|
||||
|
||||
fn serialize_request(&self, _: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
impl CommandResponse<'_> for ReplayGainStatusResponse {
|
||||
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<'_>> {
|
||||
let parts: HashMap<_, _> = parts.into_map()?;
|
||||
let replay_gain_mode = get_property!(parts, "replay_gain_mode", Text);
|
||||
|
||||
@@ -43,3 +40,8 @@ impl Command for ReplayGainStatus {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<'_, '_> for ReplayGainStatus {
|
||||
type Request = ReplayGainStatusRequest;
|
||||
type Response = ReplayGainStatusResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::VolumeValue,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -9,31 +12,11 @@ use crate::{
|
||||
|
||||
pub struct SetVol;
|
||||
|
||||
impl Command for SetVol {
|
||||
type Request = VolumeValue;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "setvol";
|
||||
single_item_command_request!(SetVol, "setvol", VolumeValue);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(SetVol);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let volume = match parts.next() {
|
||||
Some(s) => VolumeValue::from_str(s)
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, s.to_owned()))?,
|
||||
None => return Err(RequestParserError::UnexpectedEOF),
|
||||
};
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(volume)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for SetVol {
|
||||
type Request = SetVolRequest;
|
||||
type Response = SetVolResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::BoolOrOneshot,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -9,31 +12,11 @@ use crate::{
|
||||
|
||||
pub struct Single;
|
||||
|
||||
impl Command for Single {
|
||||
type Request = BoolOrOneshot;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "single";
|
||||
single_item_command_request!(Single, "single", BoolOrOneshot);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(Single);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let state = match parts.next() {
|
||||
Some(s) => crate::common::types::BoolOrOneshot::from_str(s)
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, s.to_owned()))?,
|
||||
None => return Err(RequestParserError::UnexpectedEOF),
|
||||
};
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for Single {
|
||||
type Request = SingleRequest;
|
||||
type Response = SingleResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::VolumeValue,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -9,31 +12,11 @@ use crate::{
|
||||
|
||||
pub struct Volume;
|
||||
|
||||
impl Command for Volume {
|
||||
type Request = VolumeValue;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "volume";
|
||||
single_item_command_request!(Volume, "volume", VolumeValue);
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
format!("{} {}", Self::COMMAND, request)
|
||||
}
|
||||
empty_command_response!(Volume);
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
let change = match parts.next() {
|
||||
Some(s) => VolumeValue::from_str(s)
|
||||
.map_err(|_| RequestParserError::SyntaxError(0, s.to_owned()))?,
|
||||
None => return Err(RequestParserError::UnexpectedEOF),
|
||||
};
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
Ok(change)
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
}
|
||||
impl Command<'_, '_> for Volume {
|
||||
type Request = VolumeRequest;
|
||||
type Response = VolumeResponse;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
@@ -7,25 +10,11 @@ use crate::{
|
||||
/// Clears the current error message in status (this is also accomplished by any command that starts playback)
|
||||
pub struct ClearError;
|
||||
|
||||
impl Command for ClearError {
|
||||
type Request = ();
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "clearerror";
|
||||
empty_command_request!(ClearError, "clearerror");
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
empty_command_response!(ClearError);
|
||||
|
||||
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 ClearError {
|
||||
type Request = ClearErrorRequest;
|
||||
type Response = ClearErrorResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandResponse, RequestParserError, ResponseParserError, empty_command_request,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
@@ -9,27 +11,26 @@ use crate::{
|
||||
/// Displays the song info of the current song (same song that is identified in status)
|
||||
pub struct CurrentSong;
|
||||
|
||||
empty_command_request!(CurrentSong, "currentsong");
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct CurrentSongResponse {}
|
||||
|
||||
impl Command for CurrentSong {
|
||||
type Request = ();
|
||||
type Response = CurrentSongResponse;
|
||||
const COMMAND: &'static str = "currentsong";
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
impl CommandResponse<'_> for CurrentSongResponse {
|
||||
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 CurrentSong {
|
||||
type Request = CurrentSongRequest;
|
||||
type Response = CurrentSongResponse;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
common::types::SubSystem,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -9,15 +11,24 @@ use crate::{
|
||||
|
||||
pub struct Idle;
|
||||
|
||||
pub type IdleRequest = Option<Vec<SubSystem>>;
|
||||
pub struct IdleRequest(Option<Vec<SubSystem>>);
|
||||
|
||||
impl Command for Idle {
|
||||
type Request = IdleRequest;
|
||||
type Response = ();
|
||||
impl CommandRequest<'_> for IdleRequest {
|
||||
const COMMAND: &'static str = "idle";
|
||||
|
||||
fn serialize_request(&self, request: Self::Request) -> String {
|
||||
fn into_request_enum(self) -> crate::Request {
|
||||
crate::Request::Idle(self.0)
|
||||
}
|
||||
|
||||
fn from_request_enum(request: crate::Request) -> Option<Self> {
|
||||
match request {
|
||||
crate::Request::Idle(subsystems) => Some(IdleRequest(subsystems)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize(&self) -> String {
|
||||
match &self.0 {
|
||||
Some(subsystems) => {
|
||||
let subsystems_str = subsystems
|
||||
.iter()
|
||||
@@ -30,7 +41,8 @@ impl Command for Idle {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_request(mut parts: RequestTokenizer<'_>) -> Result<Self::Request, RequestParserError> {
|
||||
fn parse(parts: RequestTokenizer<'_>) -> Result<Self, RequestParserError> {
|
||||
let mut parts = parts;
|
||||
let result = parts.next().map_or(Ok(None), |subsystems| {
|
||||
let subsystems = subsystems
|
||||
.split(',')
|
||||
@@ -41,13 +53,13 @@ impl Command for Idle {
|
||||
|
||||
debug_assert!(parts.next().is_none());
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn parse_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<Self::Response, ResponseParserError<'_>> {
|
||||
debug_assert!(parts.is_empty());
|
||||
Ok(())
|
||||
result.map(IdleRequest)
|
||||
}
|
||||
}
|
||||
|
||||
empty_command_response!(Idle);
|
||||
|
||||
impl Command<'_, '_> for Idle {
|
||||
type Request = IdleRequest;
|
||||
type Response = IdleResponse;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandResponse, RequestParserError, ResponseParserError, empty_command_request,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{
|
||||
ResponseAttributes, get_and_parse_optional_property, get_and_parse_property,
|
||||
@@ -12,6 +14,8 @@ use crate::{
|
||||
|
||||
pub struct Stats;
|
||||
|
||||
empty_command_request!(Stats, "stats");
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct StatsResponse {
|
||||
pub uptime: u64,
|
||||
@@ -23,24 +27,16 @@ pub struct StatsResponse {
|
||||
pub db_update: Option<u64>,
|
||||
}
|
||||
|
||||
impl Command for Stats {
|
||||
type Request = ();
|
||||
type Response = StatsResponse;
|
||||
const COMMAND: &'static str = "stats";
|
||||
|
||||
fn serialize_request(&self, _: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
impl CommandResponse<'_> for StatsResponse {
|
||||
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<'_>> {
|
||||
let parts: HashMap<_, _> = parts.into_map()?;
|
||||
|
||||
let uptime = get_and_parse_property!(parts, "uptime", Text);
|
||||
@@ -62,3 +58,8 @@ impl Command for Stats {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Command<'_, '_> for Stats {
|
||||
type Request = StatsRequest;
|
||||
type Response = StatsResponse;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@ use std::str::FromStr;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandResponse, RequestParserError, ResponseParserError, empty_command_request,
|
||||
},
|
||||
common::types::{Audio, BoolOrOneshot, SongId, SongPosition},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::{
|
||||
@@ -13,6 +15,10 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
pub struct Status;
|
||||
|
||||
empty_command_request!(Status, "status");
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum StatusResponseState {
|
||||
Play,
|
||||
@@ -62,124 +68,114 @@ pub struct StatusResponse {
|
||||
pub last_loaded_playlist: Option<String>,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn parse_status_response(
|
||||
parts: ResponseAttributes<'_>,
|
||||
) -> Result<StatusResponse, ResponseParserError<'_>> {
|
||||
let parts: HashMap<_, _> = parts.into_map()?;
|
||||
let partition = get_property!(parts, "partition", Text).to_string();
|
||||
impl CommandResponse<'_> for StatusResponse {
|
||||
fn into_response_enum(self) -> crate::Response {
|
||||
todo!()
|
||||
}
|
||||
|
||||
let volume = match get_property!(parts, "volume", Text) {
|
||||
"-1" => None,
|
||||
volume => Some(
|
||||
volume
|
||||
.parse()
|
||||
.map_err(|_| ResponseParserError::InvalidProperty("volume", volume))?,
|
||||
),
|
||||
};
|
||||
fn from_response_enum(response: crate::Response) -> Option<Self> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
let repeat = match get_property!(parts, "repeat", Text) {
|
||||
"0" => Ok(false),
|
||||
"1" => Ok(true),
|
||||
repeat => Err(ResponseParserError::InvalidProperty("repeat", repeat)),
|
||||
}?;
|
||||
fn parse(parts: ResponseAttributes<'_>) -> Result<Self, ResponseParserError<'_>> {
|
||||
let parts: HashMap<_, _> = parts.into_map()?;
|
||||
let partition = get_property!(parts, "partition", Text).to_string();
|
||||
|
||||
let random = match get_property!(parts, "random", Text) {
|
||||
"0" => Ok(false),
|
||||
"1" => Ok(true),
|
||||
random => Err(ResponseParserError::InvalidProperty("random", random)),
|
||||
}?;
|
||||
let volume = match get_property!(parts, "volume", Text) {
|
||||
"-1" => None,
|
||||
volume => Some(
|
||||
volume
|
||||
.parse()
|
||||
.map_err(|_| ResponseParserError::InvalidProperty("volume", volume))?,
|
||||
),
|
||||
};
|
||||
|
||||
let single = get_and_parse_property!(parts, "single", Text);
|
||||
let consume = get_and_parse_property!(parts, "consume", Text);
|
||||
let playlist: u32 = get_and_parse_property!(parts, "playlist", Text);
|
||||
let playlist_length: u64 = get_and_parse_property!(parts, "playlistlength", Text);
|
||||
let state: StatusResponseState = get_and_parse_property!(parts, "state", Text);
|
||||
let song: Option<SongPosition> = get_and_parse_optional_property!(parts, "song", Text);
|
||||
let song_id: Option<SongId> = get_and_parse_optional_property!(parts, "songid", Text);
|
||||
let next_song: Option<SongPosition> = get_and_parse_optional_property!(parts, "nextsong", Text);
|
||||
let next_song_id: Option<SongId> = get_and_parse_optional_property!(parts, "nextsongid", Text);
|
||||
let repeat = match get_property!(parts, "repeat", Text) {
|
||||
"0" => Ok(false),
|
||||
"1" => Ok(true),
|
||||
repeat => Err(ResponseParserError::InvalidProperty("repeat", repeat)),
|
||||
}?;
|
||||
|
||||
let time = match get_optional_property!(parts, "time", Text) {
|
||||
Some(time) => {
|
||||
let mut parts = time.split(':');
|
||||
let elapsed = parts
|
||||
.next()
|
||||
.ok_or(ResponseParserError::SyntaxError(0, time))?
|
||||
.parse()
|
||||
.map_err(|_| ResponseParserError::InvalidProperty("time", time))?;
|
||||
let duration = parts
|
||||
.next()
|
||||
.ok_or(ResponseParserError::SyntaxError(0, time))?
|
||||
.parse()
|
||||
.map_err(|_| ResponseParserError::InvalidProperty("time", time))?;
|
||||
Some((elapsed, duration))
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
let random = match get_property!(parts, "random", Text) {
|
||||
"0" => Ok(false),
|
||||
"1" => Ok(true),
|
||||
random => Err(ResponseParserError::InvalidProperty("random", random)),
|
||||
}?;
|
||||
|
||||
let elapsed = get_and_parse_optional_property!(parts, "elapsed", Text);
|
||||
let duration = get_and_parse_optional_property!(parts, "duration", Text);
|
||||
let bitrate = get_and_parse_optional_property!(parts, "bitrate", Text);
|
||||
let xfade = get_and_parse_optional_property!(parts, "xfade", Text);
|
||||
let mixrampdb = get_and_parse_optional_property!(parts, "mixrampdb", Text);
|
||||
let mixrampdelay = get_and_parse_optional_property!(parts, "mixrampdelay", Text);
|
||||
let audio = get_and_parse_optional_property!(parts, "audio", Text);
|
||||
let updating_db = get_and_parse_optional_property!(parts, "updating_db", Text);
|
||||
let error = get_and_parse_optional_property!(parts, "error", Text);
|
||||
let last_loaded_playlist =
|
||||
get_and_parse_optional_property!(parts, "last_loaded_playlist", Text);
|
||||
let single = get_and_parse_property!(parts, "single", Text);
|
||||
let consume = get_and_parse_property!(parts, "consume", Text);
|
||||
let playlist: u32 = get_and_parse_property!(parts, "playlist", Text);
|
||||
let playlist_length: u64 = get_and_parse_property!(parts, "playlistlength", Text);
|
||||
let state: StatusResponseState = get_and_parse_property!(parts, "state", Text);
|
||||
let song: Option<SongPosition> = get_and_parse_optional_property!(parts, "song", Text);
|
||||
let song_id: Option<SongId> = get_and_parse_optional_property!(parts, "songid", Text);
|
||||
let next_song: Option<SongPosition> =
|
||||
get_and_parse_optional_property!(parts, "nextsong", Text);
|
||||
let next_song_id: Option<SongId> =
|
||||
get_and_parse_optional_property!(parts, "nextsongid", Text);
|
||||
|
||||
Ok(StatusResponse {
|
||||
partition,
|
||||
volume,
|
||||
repeat,
|
||||
random,
|
||||
single,
|
||||
consume,
|
||||
playlist,
|
||||
playlist_length,
|
||||
state,
|
||||
song,
|
||||
song_id,
|
||||
next_song,
|
||||
next_song_id,
|
||||
time,
|
||||
elapsed,
|
||||
duration,
|
||||
bitrate,
|
||||
xfade,
|
||||
mixrampdb,
|
||||
mixrampdelay,
|
||||
audio,
|
||||
updating_db,
|
||||
error,
|
||||
last_loaded_playlist,
|
||||
})
|
||||
let time = match get_optional_property!(parts, "time", Text) {
|
||||
Some(time) => {
|
||||
let mut parts = time.split(':');
|
||||
let elapsed = parts
|
||||
.next()
|
||||
.ok_or(ResponseParserError::SyntaxError(0, time))?
|
||||
.parse()
|
||||
.map_err(|_| ResponseParserError::InvalidProperty("time", time))?;
|
||||
let duration = parts
|
||||
.next()
|
||||
.ok_or(ResponseParserError::SyntaxError(0, time))?
|
||||
.parse()
|
||||
.map_err(|_| ResponseParserError::InvalidProperty("time", time))?;
|
||||
Some((elapsed, duration))
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let elapsed = get_and_parse_optional_property!(parts, "elapsed", Text);
|
||||
let duration = get_and_parse_optional_property!(parts, "duration", Text);
|
||||
let bitrate = get_and_parse_optional_property!(parts, "bitrate", Text);
|
||||
let xfade = get_and_parse_optional_property!(parts, "xfade", Text);
|
||||
let mixrampdb = get_and_parse_optional_property!(parts, "mixrampdb", Text);
|
||||
let mixrampdelay = get_and_parse_optional_property!(parts, "mixrampdelay", Text);
|
||||
let audio = get_and_parse_optional_property!(parts, "audio", Text);
|
||||
let updating_db = get_and_parse_optional_property!(parts, "updating_db", Text);
|
||||
let error = get_and_parse_optional_property!(parts, "error", Text);
|
||||
let last_loaded_playlist =
|
||||
get_and_parse_optional_property!(parts, "last_loaded_playlist", Text);
|
||||
|
||||
Ok(StatusResponse {
|
||||
partition,
|
||||
volume,
|
||||
repeat,
|
||||
random,
|
||||
single,
|
||||
consume,
|
||||
playlist,
|
||||
playlist_length,
|
||||
state,
|
||||
song,
|
||||
song_id,
|
||||
next_song,
|
||||
next_song_id,
|
||||
time,
|
||||
elapsed,
|
||||
duration,
|
||||
bitrate,
|
||||
xfade,
|
||||
mixrampdb,
|
||||
mixrampdelay,
|
||||
audio,
|
||||
updating_db,
|
||||
error,
|
||||
last_loaded_playlist,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Status;
|
||||
|
||||
impl Command for Status {
|
||||
type Request = ();
|
||||
impl Command<'_, '_> for Status {
|
||||
type Request = StatusRequest;
|
||||
type Response = StatusResponse;
|
||||
const COMMAND: &'static str = "status";
|
||||
|
||||
fn serialize_request(&self, _request: Self::Request) -> String {
|
||||
Self::COMMAND.to_string()
|
||||
}
|
||||
|
||||
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<'_>> {
|
||||
parse_status_response(parts)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -214,7 +210,7 @@ mod tests {
|
||||
"# };
|
||||
|
||||
assert_eq!(
|
||||
Status::parse_raw_response(contents),
|
||||
Status::parse_raw_response(contents.as_bytes()),
|
||||
Ok(StatusResponse {
|
||||
partition: "default".into(),
|
||||
volume: Some(66),
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
common::types::{SongPosition, Uri},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -15,25 +17,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 +59,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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseAttributes, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseAttributes, ResponseParserError,
|
||||
empty_command_response,
|
||||
},
|
||||
common::types::{SongId, TagName, TagValue},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
};
|
||||
@@ -15,22 +18,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 +70,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;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,19 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_request,
|
||||
empty_command_response,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
common::types::{SongId, TagName},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -15,16 +17,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 +52,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;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::OneOrRange,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -9,29 +12,11 @@ use crate::{
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, RequestParserError, ResponseParserError, empty_command_response,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::SongId,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,30 +10,11 @@ use crate::{
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseAttributes, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseAttributes, ResponseParserError,
|
||||
empty_command_response,
|
||||
},
|
||||
common::types::{AbsouluteRelativeSongPosition, OneOrRange},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
};
|
||||
@@ -14,16 +17,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 +50,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;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseAttributes, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseAttributes, ResponseParserError,
|
||||
empty_command_response,
|
||||
},
|
||||
common::types::{AbsouluteRelativeSongPosition, SongId},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
};
|
||||
@@ -14,16 +17,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 +50,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;
|
||||
}
|
||||
|
||||
@@ -1,28 +1,33 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandResponse, RequestParserError, ResponseParserError, empty_command_request,
|
||||
single_item_command_request,
|
||||
},
|
||||
request_tokenizer::RequestTokenizer,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandRequest, RequestParserError, ResponseParserError, empty_command_response,
|
||||
},
|
||||
common::types::{Sort, WindowRange},
|
||||
filter::Filter,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
@@ -17,23 +19,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 +84,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;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use crate::{
|
||||
commands::{Command, RequestParserError, ResponseParserError},
|
||||
commands::{
|
||||
Command, CommandResponse, RequestParserError, ResponseParserError,
|
||||
single_item_command_request,
|
||||
},
|
||||
common::types::SongId,
|
||||
request_tokenizer::RequestTokenizer,
|
||||
response_tokenizer::ResponseAttributes,
|
||||
@@ -7,29 +10,25 @@ use crate::{
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::{
|
||||
|
||||
pub struct PlaylistInfo;
|
||||
|
||||
impl Command for PlaylistInfo {
|
||||
impl Command<'_, '_> for PlaylistInfo {
|
||||
type Request = Option<OneOrRange>;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "playlistinfo";
|
||||
|
||||
@@ -17,7 +17,7 @@ pub struct PlaylistSearchRequest {
|
||||
window: Option<WindowRange>,
|
||||
}
|
||||
|
||||
impl Command for PlaylistSearch {
|
||||
impl Command<'_, '_> for PlaylistSearch {
|
||||
type Request = PlaylistSearchRequest;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "playlistsearch";
|
||||
|
||||
@@ -15,7 +15,7 @@ pub struct PlChangesRequest {
|
||||
pub window: Option<WindowRange>,
|
||||
}
|
||||
|
||||
impl Command for PlChanges {
|
||||
impl Command<'_, '_> for PlChanges {
|
||||
type Request = PlChangesRequest;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "plchanges";
|
||||
|
||||
@@ -15,7 +15,7 @@ pub struct PlChangesPosIdRequest {
|
||||
pub window: Option<WindowRange>,
|
||||
}
|
||||
|
||||
impl Command for PlChangesPosId {
|
||||
impl Command<'_, '_> for PlChangesPosId {
|
||||
type Request = PlChangesPosIdRequest;
|
||||
type Response = ();
|
||||
const COMMAND: &'static str = "plchangesposid";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user