use mpd_protocol::{command::CommandList as RawCommandList, response::Frame};
use crate::{commands::Command, responses::TypedResponseError};
pub trait CommandList {
type Response;
fn command_list(&self) -> Option<RawCommandList>;
fn responses(self, frames: Vec<Frame>) -> Result<Self::Response, TypedResponseError>;
}
impl<C> CommandList for Vec<C>
where
C: Command,
{
type Response = Vec<C::Response>;
fn command_list(&self) -> Option<RawCommandList> {
let mut commands = self.iter().map(Command::command);
let mut raw_commands = RawCommandList::new(commands.next()?);
raw_commands.extend(commands);
Some(raw_commands)
}
fn responses(self, frames: Vec<Frame>) -> Result<Self::Response, TypedResponseError> {
assert_eq!(self.len(), frames.len());
let mut out = Vec::with_capacity(self.len());
for (command, frame) in self.into_iter().zip(frames) {
out.push(command.response(frame)?);
}
Ok(out)
}
}
macro_rules! impl_command_list_tuple {
($first_type:ident, $($further_type:ident => $further_idx:tt),*) => {
impl<$first_type, $($further_type),*> CommandList for ($first_type, $($further_type),*)
where
$first_type: Command,
$(
$further_type: Command
),*
{
type Response = ($first_type::Response, $($further_type::Response),*);
fn command_list(&self) -> Option<RawCommandList> {
#[allow(unused_mut)]
let mut commands = RawCommandList::new(self.0.command());
$(
commands.add(self.$further_idx.command());
)*
Some(commands)
}
fn responses(self, frames: Vec<Frame>) -> Result<Self::Response, TypedResponseError> {
let mut frames = frames.into_iter();
Ok((
self.0.response(frames.next().unwrap())?,
$(
self.$further_idx.response(frames.next().unwrap())?,
)*
))
}
}
};
}
impl_command_list_tuple!(A,);
impl_command_list_tuple!(A, B => 1);
impl_command_list_tuple!(A, B => 1, C => 2);
impl_command_list_tuple!(A, B => 1, C => 2, D => 3);
impl_command_list_tuple!(A, B => 1, C => 2, D => 3, E => 4);
impl_command_list_tuple!(A, B => 1, C => 2, D => 3, E => 4, F => 5);
impl_command_list_tuple!(A, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6);
impl_command_list_tuple!(A, B => 1, C => 2, D => 3, E => 4, F => 5, G => 6, H => 7);