davis 0.1.1

An CLI client for MPD.
pub struct Tags {
    native_mpd: Vec<(String, String)>,
    raw_comments: Vec<(String, String)>,
}

impl Tags {
    pub fn from_song(song: &mpdrs::Song) -> Tags {
        Tags {
            native_mpd: song.tags.clone(),
            raw_comments: vec![],
        }
    }

    pub fn from_song_and_raw_comments(
        song: &mpdrs::Song,
        raw_comments: Vec<(String, String)>,
    ) -> Tags {
        Tags {
            native_mpd: song.tags.clone(),
            raw_comments,
        }
    }

    pub fn get<'a>(&'a self, tag: &'a str) -> Vec<&'a str> {
        let mut tags = tag_filter(&*self.native_mpd, tag).collect::<Vec<_>>();
        if tags.is_empty() {
            tags.extend(tag_filter(&*self.raw_comments, tag));
        }
        tags.sort_unstable();
        tags.dedup();
        tags
    }

    pub fn get_option_joined<'a>(&'a self, tag: &'a str) -> Option<String> {
        let vals = self.get(tag);
        if vals.is_empty() {
            None
        } else {
            Some(vals.join(", "))
        }
    }

    pub fn joined(&self, keys: &[&str], sep: &str) -> Option<String> {
        keys.iter()
            .map(|k| self.get_option_joined(k))
            .collect::<Option<Vec<_>>>()
            .map(|v| v.join(sep))
    }
}

fn tag_filter<'a>(vals: &'a [(String, String)], tag: &'a str) -> impl Iterator<Item = &'a str> {
    vals.iter().filter_map(move |(k, v)| {
        if k.to_uppercase() == tag.to_uppercase() {
            Some(&**v)
        } else {
            None
        }
    })
}