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), // -- Query Commands -- // ClearError, CurrentSong, Idle(Option>), 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), Play(SongPosition), PlayId(SongId), Previous, Seek(SongPosition, TimeWithFractions), SeekId(SongId, TimeWithFractions), SeekCur(SeekMode, TimeWithFractions), Stop, // -- Queue Commands -- // // TODO: relative mode Add(String, Option), // TODO: relative mode AddId(String, Option), 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, Option), PlaylistId(SongId), PlaylistInfo(Option), PlaylistSearch(Filter, Option, Option), // TODO: which type of range? PlChanges(PlaylistVersion, Option), // TODO: which type of range? PlChangesPosId(PlaylistVersion, Option), // TODO: which type of range? Prio(Priority, WindowRange), PrioId(Priority, Vec), RangeId(SongId, TimeInterval), Shuffle(Option), Swap(SongPosition, SongPosition), SwapId(SongId, SongId), AddTagId(SongId, TagName, TagValue), ClearTagId(SongId, TagName), // -- Stored Playlist Commands -- // ListPlaylist(PlaylistName, Option), ListPlaylistInfo(PlaylistName, Option), SearchPlaylist(PlaylistName, Filter, Option), ListPlaylists, Load(PlaylistName, Option, Option), PlaylistAdd(PlaylistName, Uri, Option), PlaylistClear(PlaylistName), PlaylistDelete(PlaylistName, OneOrRange), PlaylistLength(PlaylistName), // TODO: which type of range? PlaylistMove(PlaylistName, Option, SongPosition), Rename(PlaylistName, PlaylistName), Rm(PlaylistName), Save(PlaylistName, Option), // -- Music Database Commands -- // AlbumArt(Uri, Offset), Count(Filter, Option), GetFingerprint(Uri), Find(Filter, Option, Option), FindAdd( Filter, Option, Option, Option, ), List(TagName, Option, Vec, Option), #[deprecated] ListAll(Option), #[deprecated] ListAllInfo(Option), ListFiles(Option), LsInfo(Option), ReadComments(Uri), ReadPicture(Uri, Offset), Search(Filter, Option, Option), SearchAdd( Filter, Option, Option, Option, ), SearchAddPl( PlaylistName, Filter, Option, Option, Option, ), SearchCount(Filter, Option), Update(Option), Rescan(Option), // -- 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, Option), StickerFindValue( StickerType, Uri, String, String, Option, Option, ), StickerNames, StickerTypes, StickerNamesTypes(Option), // -- Connection Commands -- // Close, Kill, Password(String), Ping, BinaryLimit(u64), TagTypes, TagTypesDisable(Vec), TagTypesEnable(Vec), TagTypesClear, TagTypesAll, TagTypesAvailable, TagTypesReset(Vec), Protocol, ProtocolDisable(Vec), ProtocolEnable(Vec), 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 { 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!(), } } }