Files
empidee/src/request.rs

592 lines
29 KiB
Rust

use serde::{Deserialize, Serialize};
use crate::commands::*;
use crate::common::types::*;
use crate::filter::Filter;
use crate::request_tokenizer::RequestTokenizer;
// TODO: SingleLineString
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Request {
CommandList(Vec<Request>),
// -- Query Commands -- //
ClearError,
CurrentSong,
Idle(Option<Vec<SubSystem>>),
Status,
Stats,
// -- Playback Commands -- //
Consume(BoolOrOneshot),
Crossfade(Seconds),
MixRampDb(f32),
MixRampDelay(Seconds),
Random(bool),
Repeat(bool),
SetVol(VolumeValue),
GetVol,
Single(BoolOrOneshot),
ReplayGainMode(ReplayGainModeMode),
ReplayGainStatus,
Volume(VolumeValue),
// -- Playback Control Commands -- //
Next,
Pause(Option<bool>),
Play(SongPosition),
PlayId(SongId),
Previous,
Seek(SongPosition, TimeWithFractions),
SeekId(SongId, TimeWithFractions),
SeekCur(SeekMode, TimeWithFractions),
Stop,
// -- Queue Commands -- //
// TODO: relative mode
Add(String, Option<SongPosition>),
// TODO: relative mode
AddId(String, Option<SongPosition>),
Clear,
Delete(OneOrRange),
DeleteId(SongId),
// TODO: account for relative moves
Move(OneOrRange, AbsouluteRelativeSongPosition),
// TODO: account for relative moves
MoveId(SongId, AbsouluteRelativeSongPosition),
Playlist,
PlaylistFind(Filter, Option<Sort>, Option<WindowRange>),
PlaylistId(SongId),
PlaylistInfo(Option<OneOrRange>),
PlaylistSearch(Filter, Option<Sort>, Option<WindowRange>),
// TODO: which type of range?
PlChanges(PlaylistVersion, Option<WindowRange>),
// TODO: which type of range?
PlChangesPosId(PlaylistVersion, Option<WindowRange>),
// TODO: which type of range?
Prio(Priority, WindowRange),
PrioId(Priority, Vec<SongId>),
RangeId(SongId, TimeInterval),
Shuffle(Option<OneOrRange>),
Swap(SongPosition, SongPosition),
SwapId(SongId, SongId),
AddTagId(SongId, TagName, TagValue),
ClearTagId(SongId, TagName),
// -- Stored Playlist Commands -- //
ListPlaylist(PlaylistName, Option<WindowRange>),
ListPlaylistInfo(PlaylistName, Option<WindowRange>),
SearchPlaylist(PlaylistName, Filter, Option<WindowRange>),
ListPlaylists,
Load(PlaylistName, Option<WindowRange>, Option<SongPosition>),
PlaylistAdd(PlaylistName, Uri, Option<SongPosition>),
PlaylistClear(PlaylistName),
PlaylistDelete(PlaylistName, OneOrRange),
PlaylistLength(PlaylistName),
// TODO: which type of range?
PlaylistMove(PlaylistName, Option<OneOrRange>, SongPosition),
Rename(PlaylistName, PlaylistName),
Rm(PlaylistName),
Save(PlaylistName, Option<SaveMode>),
// -- Music Database Commands -- //
AlbumArt(Uri, Offset),
Count(Filter, Option<GroupType>),
GetFingerprint(Uri),
Find(Filter, Option<Sort>, Option<WindowRange>),
FindAdd(
Filter,
Option<Sort>,
Option<WindowRange>,
Option<SongPosition>,
),
List(TagName, Option<Filter>, Vec<GroupType>, Option<WindowRange>),
#[deprecated]
ListAll(Option<Uri>),
#[deprecated]
ListAllInfo(Option<Uri>),
ListFiles(Option<Uri>),
LsInfo(Option<Uri>),
ReadComments(Uri),
ReadPicture(Uri, Offset),
Search(Filter, Option<Sort>, Option<WindowRange>),
SearchAdd(
Filter,
Option<Sort>,
Option<WindowRange>,
Option<SongPosition>,
),
SearchAddPl(
PlaylistName,
Filter,
Option<Sort>,
Option<WindowRange>,
Option<SongPosition>,
),
SearchCount(Filter, Option<GroupType>),
Update(Option<Uri>),
Rescan(Option<Uri>),
// -- Mount and Neighbor Commands -- //
Mount(MountPath, Uri),
Unmount(MountPath),
ListMounts,
ListNeighbors,
// -- Sticker Commands -- //
StickerGet(StickerType, Uri, String),
StickerSet(StickerType, Uri, String, String),
StickerInc(StickerType, Uri, String, usize),
StickerDec(StickerType, Uri, String, usize),
StickerDelete(StickerType, Uri, String),
StickerList(StickerType, Uri),
StickerFind(StickerType, Uri, String, Option<Sort>, Option<WindowRange>),
StickerFindValue(
StickerType,
Uri,
String,
String,
Option<Sort>,
Option<WindowRange>,
),
StickerNames,
StickerTypes,
StickerNamesTypes(Option<StickerType>),
// -- Connection Commands -- //
Close,
Kill,
Password(String),
Ping,
BinaryLimit(u64),
TagTypes,
TagTypesDisable(Vec<TagName>),
TagTypesEnable(Vec<TagName>),
TagTypesClear,
TagTypesAll,
TagTypesAvailable,
TagTypesReset(Vec<TagName>),
Protocol,
ProtocolDisable(Vec<Feature>),
ProtocolEnable(Vec<Feature>),
ProtocolClear,
ProtocolAll,
ProtocolAvailable,
// -- Partition Commands -- //
Partition(PartitionName),
ListPartitions,
NewPartition(PartitionName),
DelPartition(PartitionName),
MoveOutput(String),
// -- Audio Output Commands -- //
DisableOutput(AudioOutputId),
EnableOutput(AudioOutputId),
ToggleOutput(AudioOutputId),
Outputs,
OutputSet(AudioOutputId, String, String),
// -- Reflection Commands -- //
Config,
Commands,
NotCommands,
UrlHandlers,
Decoders,
// -- Client to Client Commands -- //
Subscribe(ChannelName),
Unsubscribe(ChannelName),
Channels,
ReadMessages,
SendMessage(ChannelName, String),
}
macro_rules! serialize_req {
($request_enum:expr, $request_struct:ty) => {
{
if let Some(request) = <$request_struct as CommandRequest<'_>>::from_request_enum($request_enum) {
return <$request_struct as CommandRequest<'_>>::serialize(&request);
} else {
panic!("Mismatched request enum and struct in serialize_request macro, this should never happen!");
}
}
};
}
macro_rules! parse_req {
($request_struct:ty, $parts:expr) => {
<$request_struct>::parse($parts).map(|req| req.into_request_enum())
};
}
impl Request {
fn serialize(self) -> String {
match self {
/* querying mpd status */
Request::ClearError => serialize_req!(self, ClearErrorRequest),
Request::CurrentSong => serialize_req!(self, CurrentSongRequest),
Request::Idle(_) => serialize_req!(self, IdleRequest),
Request::Status => serialize_req!(self, StatusRequest),
Request::Stats => serialize_req!(self, StatsRequest),
// /* playback options */
Request::Consume(_) => serialize_req!(self, ConsumeRequest),
Request::Crossfade(_) => serialize_req!(self, CrossfadeRequest),
Request::MixRampDb(_) => serialize_req!(self, MixRampDbRequest),
Request::MixRampDelay(_) => serialize_req!(self, MixRampDelayRequest),
Request::Random(_) => serialize_req!(self, RandomRequest),
Request::Repeat(_) => serialize_req!(self, RepeatRequest),
Request::SetVol(_) => serialize_req!(self, SetVolRequest),
Request::GetVol => serialize_req!(self, GetVolRequest),
Request::Single(_) => serialize_req!(self, SingleRequest),
Request::ReplayGainMode(_) => serialize_req!(self, ReplayGainModeRequest),
Request::ReplayGainStatus => serialize_req!(self, ReplayGainStatusRequest),
Request::Volume(_) => serialize_req!(self, VolumeRequest),
/* playback control */
Request::Next => serialize_req!(self, NextRequest),
Request::Pause(_) => serialize_req!(self, PauseRequest),
Request::Play(_) => serialize_req!(self, PlayRequest),
Request::PlayId(_) => serialize_req!(self, PlayIdRequest),
Request::Previous => serialize_req!(self, PreviousRequest),
Request::Seek(_, _) => serialize_req!(self, SeekRequest),
Request::SeekId(_, _) => serialize_req!(self, SeekIdRequest),
Request::SeekCur(_, _) => serialize_req!(self, SeekCurRequest),
Request::Stop => serialize_req!(self, StopRequest),
/* queue */
Request::Add(_, _) => serialize_req!(self, AddRequest),
Request::AddId(_, _) => serialize_req!(self, AddIdRequest),
Request::Clear => serialize_req!(self, ClearRequest),
Request::Delete(_) => serialize_req!(self, DeleteRequest),
Request::DeleteId(_) => serialize_req!(self, DeleteIdRequest),
Request::Move(_, _) => serialize_req!(self, MoveRequest),
Request::MoveId(_, _) => serialize_req!(self, MoveIdRequest),
Request::Playlist => serialize_req!(self, PlaylistRequest),
Request::PlaylistFind(_, _, _) => serialize_req!(self, PlaylistFindRequest),
Request::PlaylistId(_) => serialize_req!(self, PlaylistIdRequest),
Request::PlaylistInfo(_) => serialize_req!(self, PlaylistInfoRequest),
Request::PlaylistSearch(_, _, _) => serialize_req!(self, PlaylistSearchRequest),
Request::PlChanges(_, _) => serialize_req!(self, PlChangesRequest),
Request::PlChangesPosId(_, _) => serialize_req!(self, PlChangesPosIdRequest),
Request::Prio(_, _) => serialize_req!(self, PrioRequest),
Request::PrioId(_, _) => serialize_req!(self, PrioIdRequest),
Request::RangeId(_, _) => serialize_req!(self, RangeIdRequest),
Request::Shuffle(_) => serialize_req!(self, ShuffleRequest),
Request::Swap(_, _) => serialize_req!(self, SwapRequest),
Request::SwapId(_, _) => serialize_req!(self, SwapIdRequest),
Request::AddTagId(_, _, _) => serialize_req!(self, AddTagIdRequest),
Request::ClearTagId(_, _) => serialize_req!(self, ClearTagIdRequest),
/* stored playlists */
Request::ListPlaylist(_, _) => serialize_req!(self, ListPlaylistRequest),
Request::ListPlaylistInfo(_, _) => serialize_req!(self, ListPlaylistInfoRequest),
Request::SearchPlaylist(_, _, _) => serialize_req!(self, SearchPlaylistRequest),
Request::ListPlaylists => serialize_req!(self, ListPlaylistsRequest),
Request::Load(_, _, _) => serialize_req!(self, LoadRequest),
Request::PlaylistAdd(_, _, _) => serialize_req!(self, PlaylistAddRequest),
Request::PlaylistClear(_) => serialize_req!(self, PlaylistClearRequest),
Request::PlaylistDelete(_, _) => serialize_req!(self, PlaylistDeleteRequest),
Request::PlaylistLength(_) => serialize_req!(self, PlaylistLengthRequest),
Request::PlaylistMove(_, _, _) => serialize_req!(self, PlaylistMoveRequest),
Request::Rename(_, _) => serialize_req!(self, RenameRequest),
Request::Rm(_) => serialize_req!(self, RmRequest),
Request::Save(_, _) => serialize_req!(self, SaveRequest),
/* music database */
Request::AlbumArt(_, _) => serialize_req!(self, AlbumArtRequest),
Request::Count(_, _) => serialize_req!(self, CountRequest),
Request::GetFingerprint(_) => serialize_req!(self, GetFingerprintRequest),
Request::Find(_, _, _) => serialize_req!(self, FindRequest),
Request::FindAdd(_, _, _, _) => serialize_req!(self, FindAddRequest),
Request::List(_, _, _, _) => serialize_req!(self, ListRequest),
Request::ListAll(_) => serialize_req!(self, ListAllRequest),
Request::ListAllInfo(_) => serialize_req!(self, ListAllInfoRequest),
Request::ListFiles(_) => serialize_req!(self, ListFilesRequest),
Request::LsInfo(_) => serialize_req!(self, LsInfoRequest),
Request::ReadComments(_) => serialize_req!(self, ReadCommentsRequest),
Request::ReadPicture(_, _) => serialize_req!(self, ReadPictureRequest),
Request::Search(_, _, _) => serialize_req!(self, SearchRequest),
Request::SearchAdd(_, _, _, _) => serialize_req!(self, SearchAddRequest),
Request::SearchAddPl(_, _, _, _, _) => serialize_req!(self, SearchAddPlRequest),
Request::SearchCount(_, _) => serialize_req!(self, SearchCountRequest),
Request::Update(_) => serialize_req!(self, UpdateRequest),
Request::Rescan(_) => serialize_req!(self, RescanRequest),
/* mounts and neighbors */
Request::Mount(_, _) => serialize_req!(self, MountRequest),
Request::Unmount(_) => serialize_req!(self, UnmountRequest),
Request::ListMounts => serialize_req!(self, ListMountsRequest),
Request::ListNeighbors => serialize_req!(self, ListNeighborsRequest),
/* stickers */
Request::StickerGet(_, _, _) => serialize_req!(self, StickerGetRequest),
Request::StickerSet(_, _, _, _) => serialize_req!(self, StickerSetRequest),
Request::StickerInc(_, _, _, _) => serialize_req!(self, StickerIncRequest),
Request::StickerDec(_, _, _, _) => serialize_req!(self, StickerDecRequest),
Request::StickerDelete(_, _, _) => serialize_req!(self, StickerDeleteRequest),
Request::StickerList(_, _) => serialize_req!(self, StickerListRequest),
Request::StickerFind(_, _, _, _, _) => serialize_req!(self, StickerFindRequest),
Request::StickerNames => serialize_req!(self, StickerNamesRequest),
Request::StickerTypes => serialize_req!(self, StickerTypesRequest),
Request::StickerNamesTypes(_) => serialize_req!(self, StickerNamesTypesRequest),
/* connection settings */
Request::Close => serialize_req!(self, CloseRequest),
Request::Kill => serialize_req!(self, KillRequest),
Request::Password(_) => serialize_req!(self, PasswordRequest),
Request::Ping => serialize_req!(self, PingRequest),
Request::BinaryLimit(_) => serialize_req!(self, BinaryLimitRequest),
Request::TagTypes => serialize_req!(self, TagTypesRequest),
Request::TagTypesDisable(_) => serialize_req!(self, TagTypesDisableRequest),
Request::TagTypesEnable(_) => serialize_req!(self, TagTypesEnableRequest),
Request::TagTypesClear => serialize_req!(self, TagTypesClearRequest),
Request::TagTypesAll => serialize_req!(self, TagTypesAllRequest),
Request::TagTypesAvailable => serialize_req!(self, TagTypesAvailableRequest),
Request::TagTypesReset(_) => serialize_req!(self, TagTypesResetRequest),
Request::Protocol => serialize_req!(self, ProtocolRequest),
Request::ProtocolDisable(_) => serialize_req!(self, ProtocolDisableRequest),
Request::ProtocolEnable(_) => serialize_req!(self, ProtocolEnableRequest),
Request::ProtocolClear => serialize_req!(self, ProtocolClearRequest),
Request::ProtocolAll => serialize_req!(self, ProtocolAllRequest),
Request::ProtocolAvailable => serialize_req!(self, ProtocolAvailableRequest),
/* partition commands */
Request::Partition(_) => serialize_req!(self, PartitionRequest),
Request::ListPartitions => serialize_req!(self, ListPartitionsRequest),
Request::NewPartition(_) => serialize_req!(self, NewPartitionRequest),
Request::DelPartition(_) => serialize_req!(self, DelPartitionRequest),
Request::MoveOutput(_) => serialize_req!(self, MoveOutputRequest),
/* audio output devices */
Request::DisableOutput(_) => serialize_req!(self, DisableOutputRequest),
Request::EnableOutput(_) => serialize_req!(self, EnableOutputRequest),
Request::ToggleOutput(_) => serialize_req!(self, ToggleOutputRequest),
Request::Outputs => serialize_req!(self, OutputsRequest),
Request::OutputSet(_, _, _) => serialize_req!(self, OutputSetRequest),
/* reflection */
Request::Config => serialize_req!(self, ConfigRequest),
Request::Commands => serialize_req!(self, CommandsRequest),
Request::NotCommands => serialize_req!(self, NotCommandsRequest),
Request::UrlHandlers => serialize_req!(self, UrlHandlersRequest),
Request::Decoders => serialize_req!(self, DecodersRequest),
/* client to client */
Request::Subscribe(_) => serialize_req!(self, SubscribeRequest),
Request::Unsubscribe(_) => serialize_req!(self, UnsubscribeRequest),
Request::Channels => serialize_req!(self, ChannelsRequest),
Request::ReadMessages => serialize_req!(self, ReadMessagesRequest),
Request::SendMessage(_, _) => serialize_req!(self, SendMessageRequest),
_ => unimplemented!(),
}
}
// TODO: upon encountering an error, there should be a function that lets you skip to the next OK,
// and continue execution. Maybe "parse_next_or_skip(&str) -> RequestParserResponse", which
// could skip stuff internally? Or do we want to report back the error with the entire command
// and let the library user decide what to do?
//
// TODO: should this return the remaining &str as well?
pub fn parse_next(raw: &str) -> Result<Self, RequestParserError> {
let (line, rest) = raw
.split_once('\n')
.ok_or(RequestParserError::UnexpectedEOF)?;
let mut parts = RequestTokenizer::new(line);
match parts
.next()
.ok_or(RequestParserError::SyntaxError(0, line.to_string()))?
.trim()
{
"command_list_begin" => {
let mut commands = Vec::new();
let mut i = 1;
loop {
i += 1;
let (line, _rest) = rest
.split_once('\n')
.ok_or(RequestParserError::MissingCommandListEnd(i))?;
match line.trim() {
"command_list_begin" => {
return Err(RequestParserError::NestedCommandList(i));
}
"command_list_end" => {
return Ok(Request::CommandList(commands));
}
input => {
let command = Request::parse_next(input)?;
commands.push(command);
}
}
}
}
"command_list_end" => Err(RequestParserError::UnexpectedCommandListEnd(0)),
/* querying mpd status */
ClearErrorRequest::COMMAND => parse_req!(ClearErrorRequest, parts),
CurrentSongRequest::COMMAND => parse_req!(CurrentSongRequest, parts),
IdleRequest::COMMAND => parse_req!(IdleRequest, parts),
StatusRequest::COMMAND => parse_req!(StatusRequest, parts),
StatsRequest::COMMAND => parse_req!(StatsRequest, parts),
/* playback options */
ConsumeRequest::COMMAND => parse_req!(ConsumeRequest, parts),
CrossfadeRequest::COMMAND => parse_req!(CrossfadeRequest, parts),
MixRampDbRequest::COMMAND => parse_req!(MixRampDbRequest, parts),
MixRampDelayRequest::COMMAND => parse_req!(MixRampDelayRequest, parts),
RandomRequest::COMMAND => parse_req!(RandomRequest, parts),
RepeatRequest::COMMAND => parse_req!(RepeatRequest, parts),
SetVolRequest::COMMAND => parse_req!(SetVolRequest, parts),
GetVolRequest::COMMAND => parse_req!(GetVolRequest, parts),
SingleRequest::COMMAND => parse_req!(SingleRequest, parts),
ReplayGainModeRequest::COMMAND => parse_req!(ReplayGainModeRequest, parts),
ReplayGainStatusRequest::COMMAND => parse_req!(ReplayGainStatusRequest, parts),
VolumeRequest::COMMAND => parse_req!(VolumeRequest, parts),
/* playback control */
NextRequest::COMMAND => parse_req!(NextRequest, parts),
PauseRequest::COMMAND => parse_req!(PauseRequest, parts),
PlayRequest::COMMAND => parse_req!(PlayRequest, parts),
PlayIdRequest::COMMAND => parse_req!(PlayIdRequest, parts),
PreviousRequest::COMMAND => parse_req!(PreviousRequest, parts),
SeekRequest::COMMAND => parse_req!(SeekRequest, parts),
SeekIdRequest::COMMAND => parse_req!(SeekIdRequest, parts),
SeekCurRequest::COMMAND => parse_req!(SeekCurRequest, parts),
StopRequest::COMMAND => parse_req!(StopRequest, parts),
/* queue */
AddRequest::COMMAND => parse_req!(AddRequest, parts),
AddIdRequest::COMMAND => parse_req!(AddIdRequest, parts),
ClearRequest::COMMAND => parse_req!(ClearRequest, parts),
DeleteRequest::COMMAND => parse_req!(DeleteRequest, parts),
DeleteIdRequest::COMMAND => parse_req!(DeleteIdRequest, parts),
MoveRequest::COMMAND => parse_req!(MoveRequest, parts),
MoveIdRequest::COMMAND => parse_req!(MoveIdRequest, parts),
PlaylistRequest::COMMAND => parse_req!(PlaylistRequest, parts),
PlaylistFindRequest::COMMAND => parse_req!(PlaylistFindRequest, parts),
PlaylistIdRequest::COMMAND => parse_req!(PlaylistIdRequest, parts),
PlaylistInfoRequest::COMMAND => parse_req!(PlaylistInfoRequest, parts),
PlaylistSearchRequest::COMMAND => parse_req!(PlaylistSearchRequest, parts),
PlChangesRequest::COMMAND => parse_req!(PlChangesRequest, parts),
PlChangesPosIdRequest::COMMAND => parse_req!(PlChangesPosIdRequest, parts),
PrioRequest::COMMAND => parse_req!(PrioRequest, parts),
PrioIdRequest::COMMAND => parse_req!(PrioIdRequest, parts),
RangeIdRequest::COMMAND => parse_req!(RangeIdRequest, parts),
ShuffleRequest::COMMAND => parse_req!(ShuffleRequest, parts),
SwapRequest::COMMAND => parse_req!(SwapRequest, parts),
SwapIdRequest::COMMAND => parse_req!(SwapIdRequest, parts),
AddTagIdRequest::COMMAND => parse_req!(AddTagIdRequest, parts),
ClearTagIdRequest::COMMAND => parse_req!(ClearTagIdRequest, parts),
/* stored playlists */
ListPlaylistRequest::COMMAND => parse_req!(ListPlaylistRequest, parts),
ListPlaylistInfoRequest::COMMAND => parse_req!(ListPlaylistInfoRequest, parts),
SearchPlaylistRequest::COMMAND => parse_req!(SearchPlaylistRequest, parts),
ListPlaylistsRequest::COMMAND => parse_req!(ListPlaylistsRequest, parts),
LoadRequest::COMMAND => parse_req!(LoadRequest, parts),
PlaylistAddRequest::COMMAND => parse_req!(PlaylistAddRequest, parts),
PlaylistClearRequest::COMMAND => parse_req!(PlaylistClearRequest, parts),
PlaylistDeleteRequest::COMMAND => parse_req!(PlaylistDeleteRequest, parts),
PlaylistLengthRequest::COMMAND => parse_req!(PlaylistLengthRequest, parts),
PlaylistMoveRequest::COMMAND => parse_req!(PlaylistMoveRequest, parts),
RenameRequest::COMMAND => parse_req!(RenameRequest, parts),
RmRequest::COMMAND => parse_req!(RmRequest, parts),
SaveRequest::COMMAND => parse_req!(SaveRequest, parts),
/* music database */
AlbumArtRequest::COMMAND => parse_req!(AlbumArtRequest, parts),
CountRequest::COMMAND => parse_req!(CountRequest, parts),
GetFingerprintRequest::COMMAND => parse_req!(GetFingerprintRequest, parts),
FindRequest::COMMAND => parse_req!(FindRequest, parts),
FindAddRequest::COMMAND => parse_req!(FindAddRequest, parts),
ListRequest::COMMAND => parse_req!(ListRequest, parts),
ListAllRequest::COMMAND => parse_req!(ListAllRequest, parts),
ListAllInfoRequest::COMMAND => parse_req!(ListAllInfoRequest, parts),
ListFilesRequest::COMMAND => parse_req!(ListFilesRequest, parts),
LsInfoRequest::COMMAND => parse_req!(LsInfoRequest, parts),
ReadCommentsRequest::COMMAND => parse_req!(ReadCommentsRequest, parts),
ReadPictureRequest::COMMAND => parse_req!(ReadPictureRequest, parts),
SearchRequest::COMMAND => parse_req!(SearchRequest, parts),
SearchAddRequest::COMMAND => parse_req!(SearchAddRequest, parts),
SearchAddPlRequest::COMMAND => parse_req!(SearchAddPlRequest, parts),
SearchCountRequest::COMMAND => parse_req!(SearchCountRequest, parts),
UpdateRequest::COMMAND => parse_req!(UpdateRequest, parts),
RescanRequest::COMMAND => parse_req!(RescanRequest, parts),
/* mounts and neighbors */
MountRequest::COMMAND => parse_req!(MountRequest, parts),
UnmountRequest::COMMAND => parse_req!(UnmountRequest, parts),
ListMountsRequest::COMMAND => parse_req!(ListMountsRequest, parts),
ListNeighborsRequest::COMMAND => parse_req!(ListNeighborsRequest, parts),
/* stickers */
StickerGetRequest::COMMAND => parse_req!(StickerGetRequest, parts),
StickerSetRequest::COMMAND => parse_req!(StickerSetRequest, parts),
StickerIncRequest::COMMAND => parse_req!(StickerIncRequest, parts),
StickerDecRequest::COMMAND => parse_req!(StickerDecRequest, parts),
StickerDeleteRequest::COMMAND => parse_req!(StickerDeleteRequest, parts),
StickerListRequest::COMMAND => parse_req!(StickerListRequest, parts),
StickerFindRequest::COMMAND => parse_req!(StickerFindRequest, parts),
StickerNamesRequest::COMMAND => parse_req!(StickerNamesRequest, parts),
StickerTypesRequest::COMMAND => parse_req!(StickerTypesRequest, parts),
StickerNamesTypesRequest::COMMAND => parse_req!(StickerNamesTypesRequest, parts),
/* connection settings */
CloseRequest::COMMAND => parse_req!(CloseRequest, parts),
KillRequest::COMMAND => parse_req!(KillRequest, parts),
PasswordRequest::COMMAND => parse_req!(PasswordRequest, parts),
PingRequest::COMMAND => parse_req!(PingRequest, parts),
BinaryLimitRequest::COMMAND => parse_req!(BinaryLimitRequest, parts),
TagTypesRequest::COMMAND => parse_req!(TagTypesRequest, parts),
TagTypesDisableRequest::COMMAND => parse_req!(TagTypesDisableRequest, parts),
TagTypesEnableRequest::COMMAND => parse_req!(TagTypesEnableRequest, parts),
TagTypesClearRequest::COMMAND => parse_req!(TagTypesClearRequest, parts),
TagTypesAllRequest::COMMAND => parse_req!(TagTypesAllRequest, parts),
TagTypesAvailableRequest::COMMAND => parse_req!(TagTypesAvailableRequest, parts),
TagTypesResetRequest::COMMAND => parse_req!(TagTypesResetRequest, parts),
ProtocolRequest::COMMAND => parse_req!(ProtocolRequest, parts),
ProtocolDisableRequest::COMMAND => parse_req!(ProtocolDisableRequest, parts),
ProtocolEnableRequest::COMMAND => parse_req!(ProtocolEnableRequest, parts),
ProtocolClearRequest::COMMAND => parse_req!(ProtocolClearRequest, parts),
ProtocolAllRequest::COMMAND => parse_req!(ProtocolAllRequest, parts),
ProtocolAvailableRequest::COMMAND => parse_req!(ProtocolAvailableRequest, parts),
/* partition commands */
PartitionRequest::COMMAND => parse_req!(PartitionRequest, parts),
ListPartitionsRequest::COMMAND => parse_req!(ListPartitionsRequest, parts),
NewPartitionRequest::COMMAND => parse_req!(NewPartitionRequest, parts),
DelPartitionRequest::COMMAND => parse_req!(DelPartitionRequest, parts),
MoveOutputRequest::COMMAND => parse_req!(MoveOutputRequest, parts),
/* audio output devices */
DisableOutputRequest::COMMAND => parse_req!(DisableOutputRequest, parts),
EnableOutputRequest::COMMAND => parse_req!(EnableOutputRequest, parts),
ToggleOutputRequest::COMMAND => parse_req!(ToggleOutputRequest, parts),
OutputsRequest::COMMAND => parse_req!(OutputsRequest, parts),
OutputSetRequest::COMMAND => parse_req!(OutputSetRequest, parts),
/* reflection */
ConfigRequest::COMMAND => parse_req!(ConfigRequest, parts),
CommandsRequest::COMMAND => parse_req!(CommandsRequest, parts),
NotCommandsRequest::COMMAND => parse_req!(NotCommandsRequest, parts),
UrlHandlersRequest::COMMAND => parse_req!(UrlHandlersRequest, parts),
DecodersRequest::COMMAND => parse_req!(DecodersRequest, parts),
/* client to client */
SubscribeRequest::COMMAND => parse_req!(SubscribeRequest, parts),
UnsubscribeRequest::COMMAND => parse_req!(UnsubscribeRequest, parts),
ChannelsRequest::COMMAND => parse_req!(ChannelsRequest, parts),
ReadMessagesRequest::COMMAND => parse_req!(ReadMessagesRequest, parts),
SendMessageRequest::COMMAND => parse_req!(SendMessageRequest, parts),
_ => unimplemented!(),
}
}
}