Skip to content

Commit e3c8bd6

Browse files
authored
Merge pull request kstep#23 from tomprince/more-response-helpers
Add some more helpers for parsing responses.
2 parents b9683ac + 258f137 commit e3c8bd6

File tree

5 files changed

+90
-146
lines changed

5 files changed

+90
-146
lines changed

src/client.rs

Lines changed: 23 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -209,19 +209,20 @@ impl<S: Read + Write> Client<S> {
209209
"playlistinfo"
210210
};
211211
self.run_command(command, pos.to_range())
212-
.and_then(|_| self.read_pairs().split("file").map(|v| v.and_then(FromMap::from_map)).collect())
212+
.and_then(|_| self.read_structs("file"))
213213
}
214214

215215
/// List all songs in a play queue
216216
pub fn queue(&mut self) -> Result<Vec<Song>> {
217217
self.run_command("playlistinfo", ())
218-
.and_then(|_| self.read_pairs().split("file").map(|v| v.and_then(FromMap::from_map)).collect())
218+
.and_then(|_| self.read_structs("file"))
219219
}
220220

221221
/// Get current playing song
222222
pub fn currentsong(&mut self) -> Result<Option<Song>> {
223223
self.run_command("currentsong", ())
224-
.and_then(|_| self.read_struct::<Song>().map(|s| if s.place.is_none() { None } else { Some(s) }))
224+
.and_then(|_| self.read_struct::<Song>())
225+
.map(|s| if s.place.is_none() { None } else { Some(s) })
225226
}
226227

227228
/// Clear current queue
@@ -233,27 +234,20 @@ impl<S: Read + Write> Client<S> {
233234
/// List all changes in a queue since given version
234235
pub fn changes(&mut self, version: u32) -> Result<Vec<Song>> {
235236
self.run_command("plchanges", version)
236-
.and_then(|_| self.read_pairs().split("file").map(|v| v.and_then(FromMap::from_map)).collect())
237+
.and_then(|_| self.read_structs("file"))
237238
}
238239

239240
/// Append a song into a queue
240241
pub fn push<P: AsRef<str>>(&mut self, path: P) -> Result<Id> {
241242
self.run_command("addid", path.as_ref())
242243
.and_then(|_| self.read_field("Id"))
243-
.and_then(|v| {
244-
self.expect_ok()
245-
.and_then(|_| v.parse().map_err(From::from).map(Id))
246-
})
244+
.map(Id)
247245
}
248246

249247
/// Insert a song into a given position in a queue
250248
pub fn insert<P: AsRef<str>>(&mut self, path: P, pos: usize) -> Result<usize> {
251249
self.run_command("addid", (path.as_ref(), pos))
252250
.and_then(|_| self.read_field("Id"))
253-
.and_then(|v| {
254-
self.expect_ok()
255-
.and_then(|_| v.parse().map_err(From::from))
256-
})
257251
}
258252

259253
/// Delete a song (at some position) or several songs (in a range) from a queue
@@ -338,13 +332,13 @@ impl<S: Read + Write> Client<S> {
338332
/// List all playlists
339333
pub fn playlists(&mut self) -> Result<Vec<Playlist>> {
340334
self.run_command("listplaylists", ())
341-
.and_then(|_| self.read_pairs().split("playlist").map(|v| v.and_then(FromMap::from_map)).collect())
335+
.and_then(|_| self.read_structs("playlist"))
342336
}
343337

344338
/// List all songs in a playlist
345339
pub fn playlist<N: ToPlaylistName>(&mut self, name: N) -> Result<Vec<Song>> {
346340
self.run_command("listplaylistinfo", name.to_name())
347-
.and_then(|_| self.read_pairs().split("file").map(|v| v.and_then(FromMap::from_map)).collect())
341+
.and_then(|_| self.read_structs("file"))
348342
}
349343

350344
/// Load playlist into queue
@@ -407,20 +401,12 @@ impl<S: Read + Write> Client<S> {
407401
pub fn rescan(&mut self) -> Result<u32> {
408402
self.run_command("rescan", ())
409403
.and_then(|_| self.read_field("updating_db"))
410-
.and_then(|v| {
411-
self.expect_ok()
412-
.and_then(|_| v.parse().map_err(From::from))
413-
})
414404
}
415405

416406
/// Run database update, i.e. remove non-existing files from DB
417407
pub fn update(&mut self) -> Result<u32> {
418408
self.run_command("update", ())
419409
.and_then(|_| self.read_field("updating_db"))
420-
.and_then(|v| {
421-
self.expect_ok()
422-
.and_then(|_| v.parse().map_err(From::from))
423-
})
424410
}
425411
// }}}
426412

@@ -447,12 +433,7 @@ impl<S: Read + Write> Client<S> {
447433

448434
fn find_generic(&mut self, cmd: &str, query: &Query, window: Window) -> Result<Vec<Song>> {
449435
self.run_command(cmd, (query, window))
450-
.and_then(|_| {
451-
self.read_pairs()
452-
.split("file")
453-
.map(|v| v.and_then(FromMap::from_map))
454-
.collect()
455-
})
436+
.and_then(|_| self.read_structs("file"))
456437
}
457438

458439
// }}}
@@ -461,7 +442,7 @@ impl<S: Read + Write> Client<S> {
461442
/// List all outputs
462443
pub fn outputs(&mut self) -> Result<Vec<Output>> {
463444
self.run_command("outputs", ())
464-
.and_then(|_| self.read_pairs().split("outputid").map(|v| v.and_then(FromMap::from_map)).collect())
445+
.and_then(|_| self.read_structs("outputid"))
465446
}
466447

467448
/// Set given output enabled state
@@ -497,121 +478,50 @@ impl<S: Read + Write> Client<S> {
497478
pub fn music_directory(&mut self) -> Result<String> {
498479
self.run_command("config", ())
499480
.and_then(|_| self.read_field("music_directory"))
500-
.and_then(|d| self.expect_ok().map(|_| d))
501481
}
502482

503483
/// List all available commands
504484
pub fn commands(&mut self) -> Result<Vec<String>> {
505485
self.run_command("commands", ())
506-
.and_then(|_| {
507-
self.read_pairs()
508-
.filter(|r| {
509-
r.as_ref()
510-
.map(|&(ref a, _)| *a == "command")
511-
.unwrap_or(true)
512-
})
513-
.map(|r| r.map(|(_, b)| b))
514-
.collect()
515-
})
486+
.and_then(|_| self.read_list("command"))
516487
}
517488

518489
/// List all forbidden commands
519490
pub fn notcommands(&mut self) -> Result<Vec<String>> {
520491
self.run_command("notcommands", ())
521-
.and_then(|_| {
522-
self.read_pairs()
523-
.filter(|r| {
524-
r.as_ref()
525-
.map(|&(ref a, _)| *a == "command")
526-
.unwrap_or(true)
527-
})
528-
.map(|r| r.map(|(_, b)| b))
529-
.collect()
530-
})
492+
.and_then(|_| self.read_list("command"))
531493
}
532494

533495
/// List all available URL handlers
534496
pub fn urlhandlers(&mut self) -> Result<Vec<String>> {
535497
self.run_command("urlhandlers", ())
536-
.and_then(|_| {
537-
self.read_pairs()
538-
.filter(|r| {
539-
r.as_ref()
540-
.map(|&(ref a, _)| *a == "handler")
541-
.unwrap_or(true)
542-
})
543-
.map(|r| r.map(|(_, b)| b))
544-
.collect()
545-
})
498+
.and_then(|_| self.read_list("handler"))
546499
}
547500

548501
/// List all supported tag types
549502
pub fn tagtypes(&mut self) -> Result<Vec<String>> {
550503
self.run_command("tagtypes", ())
551-
.and_then(|_| {
552-
self.read_pairs()
553-
.filter(|r| {
554-
r.as_ref()
555-
.map(|&(ref a, _)| *a == "tagtype")
556-
.unwrap_or(true)
557-
})
558-
.map(|r| r.map(|(_, b)| b))
559-
.collect()
560-
})
504+
.and_then(|_| self.read_list("tagtype"))
561505
}
562506

563507
/// List all available decoder plugins
564508
pub fn decoders(&mut self) -> Result<Vec<Plugin>> {
565-
try!(self.run_command("decoders", ()));
566-
567-
let mut result = Vec::new();
568-
let mut plugin: Option<Plugin> = None;
569-
for reply in self.read_pairs() {
570-
let (a, b) = try!(reply);
571-
match &*a {
572-
"plugin" => {
573-
plugin.map(|p| result.push(p));
574-
575-
plugin = Some(Plugin {
576-
name: b,
577-
suffixes: Vec::new(),
578-
mime_types: Vec::new(),
579-
});
580-
}
581-
"mime_type" => {
582-
plugin.as_mut().map(|p| p.mime_types.push(b));
583-
}
584-
"suffix" => {
585-
plugin.as_mut().map(|p| p.suffixes.push(b));
586-
}
587-
_ => unreachable!(),
588-
}
589-
}
590-
plugin.map(|p| result.push(p));
591-
Ok(result)
509+
self.run_command("decoders", ()).and_then(|_| self.read_struct())
592510
}
593511
// }}}
594512

595513
// Messaging {{{
596514
/// List all channels available for current connection
597515
pub fn channels(&mut self) -> Result<Vec<Channel>> {
598516
self.run_command("channels", ())
599-
.and_then(|_| {
600-
self.read_pairs()
601-
.filter(|r| {
602-
r.as_ref()
603-
.map(|&(ref a, _)| *a == "channel")
604-
.unwrap_or(true)
605-
})
606-
.map(|r| r.map(|(_, b)| unsafe { Channel::new_unchecked(b) }))
607-
.collect()
608-
})
517+
.and_then(|_| self.read_list("channel"))
518+
.map(|v| v.into_iter().map(|b| unsafe { Channel::new_unchecked(b) }).collect())
609519
}
610520

611521
/// Read queued messages from subscribed channels
612522
pub fn readmessages(&mut self) -> Result<Vec<Message>> {
613523
self.run_command("readmessages", ())
614-
.and_then(|_| self.read_pairs().split("channel").map(|v| v.and_then(FromMap::from_map)).collect())
524+
.and_then(|_| self.read_structs("channel"))
615525
}
616526

617527
/// Send a message to a channel
@@ -639,13 +549,13 @@ impl<S: Read + Write> Client<S> {
639549
/// These mounts exist inside MPD process only, thus they can work without root permissions.
640550
pub fn mounts(&mut self) -> Result<Vec<Mount>> {
641551
self.run_command("listmounts", ())
642-
.and_then(|_| self.read_pairs().split("mount").map(|v| v.and_then(FromMap::from_map)).collect())
552+
.and_then(|_| self.read_structs("mount"))
643553
}
644554

645555
/// List all network neighbors, which can be potentially mounted
646556
pub fn neighbors(&mut self) -> Result<Vec<Neighbor>> {
647557
self.run_command("listneighbors", ())
648-
.and_then(|_| self.read_pairs().split("neighbor").map(|v| v.and_then(FromMap::from_map)).collect())
558+
.and_then(|_| self.read_structs("neighbor"))
649559
}
650560

651561
/// Mount given neighbor to a mount point
@@ -670,7 +580,6 @@ impl<S: Read + Write> Client<S> {
670580
pub fn sticker(&mut self, typ: &str, uri: &str, name: &str) -> Result<String> {
671581
self.run_command("sticker set", (typ, uri, name))
672582
.and_then(|_| self.read_field("sticker"))
673-
.and_then(|s| self.expect_ok().map(|_| s))
674583
}
675584

676585
/// Set sticker value for a given object, identified by type and uri
@@ -694,16 +603,8 @@ impl<S: Read + Write> Client<S> {
694603
/// List all stickers from a given object, identified by type and uri
695604
pub fn stickers(&mut self, typ: &str, uri: &str) -> Result<Vec<String>> {
696605
self.run_command("sticker list", (typ, uri))
697-
.and_then(|_| {
698-
self.read_pairs()
699-
.filter(|r| {
700-
r.as_ref()
701-
.map(|&(ref a, _)| *a == "sticker")
702-
.unwrap_or(true)
703-
})
704-
.map(|r| r.map(|(_, b)| b.splitn(2, '=').nth(1).map(|s| s.to_owned()).unwrap()))
705-
.collect()
706-
})
606+
.and_then(|_| self.read_list("sticker"))
607+
.map(|v| v.into_iter().map(|b| b.splitn(2, '=').nth(1).map(|s| s.to_owned()).unwrap()).collect())
707608
}
708609

709610
/// List all (file, sticker) pairs for sticker name and objects of given type
@@ -729,16 +630,7 @@ impl<S: Read + Write> Client<S> {
729630
/// with a tag set to given value
730631
pub fn find_sticker_eq(&mut self, typ: &str, uri: &str, name: &str, value: &str) -> Result<Vec<String>> {
731632
self.run_command("sticker find", (typ, uri, name, value))
732-
.and_then(|_| {
733-
self.read_pairs()
734-
.filter(|r| {
735-
r.as_ref()
736-
.map(|&(ref a, _)| *a == "file")
737-
.unwrap_or(true)
738-
})
739-
.map(|r| r.map(|(_, b)| b))
740-
.collect()
741-
})
633+
.and_then(|_| self.read_list("file"))
742634
}
743635
// }}}
744636
}

src/error.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use std::io::Error as IoError;
1919
use std::num::{ParseFloatError, ParseIntError};
2020
use std::result;
2121
use std::str::FromStr;
22+
use std::string::ParseError as StringParseError;
2223
use time::ParseError as TimeParseError;
2324

2425
// Server errors {{{
@@ -345,6 +346,12 @@ impl From<ParseFloatError> for ParseError {
345346
ParseError::BadFloat(e)
346347
}
347348
}
349+
350+
impl From<StringParseError> for ParseError {
351+
fn from(e: StringParseError) -> ParseError {
352+
match e {}
353+
}
354+
}
348355
// }}}
349356

350357
// Protocol errors {{{

src/idle.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,8 @@ impl<'a, S: 'a + Read + Write> IdleGuard<'a, S> {
125125
/// Get list of subsystems with new events, interrupting idle mode in process
126126
pub fn get(self) -> Result<Vec<Subsystem>, Error> {
127127
let result = self.0
128-
.read_pairs()
129-
.filter(|r| {
130-
r.as_ref()
131-
.map(|&(ref a, _)| *a == "changed")
132-
.unwrap_or(true)
133-
})
134-
.map(|r| r.and_then(|(_, b)| b.parse().map_err(From::from)))
135-
.collect();
128+
.read_list("changed")
129+
.and_then(|v| v.into_iter().map(|b| b.parse().map_err(From::from)).collect());
136130
forget(self);
137131
result
138132
}

src/plugin.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
//! The module defines decoder plugin data structures
22
3+
use convert::FromIter;
4+
use error::Error;
5+
36
/// Decoder plugin
47
#[derive(Clone, Debug, PartialEq, RustcEncodable)]
58
pub struct Plugin {
@@ -10,3 +13,33 @@ pub struct Plugin {
1013
/// supported MIME-types
1114
pub mime_types: Vec<String>,
1215
}
16+
17+
impl FromIter for Vec<Plugin> {
18+
fn from_iter<I: Iterator<Item = Result<(String, String), Error>>>(iter: I) -> Result<Self, Error> {
19+
let mut result = Vec::new();
20+
let mut plugin: Option<Plugin> = None;
21+
for reply in iter {
22+
let (a, b) = try!(reply);
23+
match &*a {
24+
"plugin" => {
25+
plugin.map(|p| result.push(p));
26+
27+
plugin = Some(Plugin {
28+
name: b,
29+
suffixes: Vec::new(),
30+
mime_types: Vec::new(),
31+
});
32+
}
33+
"mime_type" => {
34+
plugin.as_mut().map(|p| p.mime_types.push(b));
35+
}
36+
"suffix" => {
37+
plugin.as_mut().map(|p| p.suffixes.push(b));
38+
}
39+
_ => unreachable!(),
40+
}
41+
}
42+
plugin.map(|p| result.push(p));
43+
Ok(result)
44+
}
45+
}

0 commit comments

Comments
 (0)