use std::ffi::{CStr, CString};
use mpdclient_sys::{
mpd_recv_pair_tag, mpd_return_pair, mpd_tag_name, mpd_tag_name_iparse,
mpd_tag_type_MPD_TAG_ALBUM, mpd_tag_type_MPD_TAG_ALBUM_ARTIST,
mpd_tag_type_MPD_TAG_ALBUM_ARTIST_SORT, mpd_tag_type_MPD_TAG_ALBUM_SORT,
mpd_tag_type_MPD_TAG_ARTIST, mpd_tag_type_MPD_TAG_ARTIST_SORT, mpd_tag_type_MPD_TAG_COMMENT,
mpd_tag_type_MPD_TAG_COMPOSER, mpd_tag_type_MPD_TAG_COMPOSER_SORT,
mpd_tag_type_MPD_TAG_CONDUCTOR, mpd_tag_type_MPD_TAG_DATE, mpd_tag_type_MPD_TAG_DISC,
mpd_tag_type_MPD_TAG_ENSEMBLE, mpd_tag_type_MPD_TAG_GENRE, mpd_tag_type_MPD_TAG_GROUPING,
mpd_tag_type_MPD_TAG_LABEL, mpd_tag_type_MPD_TAG_LOCATION, mpd_tag_type_MPD_TAG_MOOD,
mpd_tag_type_MPD_TAG_MOVEMENT, mpd_tag_type_MPD_TAG_MOVEMENTNUMBER,
mpd_tag_type_MPD_TAG_MUSICBRAINZ_ALBUMARTISTID, mpd_tag_type_MPD_TAG_MUSICBRAINZ_ALBUMID,
mpd_tag_type_MPD_TAG_MUSICBRAINZ_ARTISTID, mpd_tag_type_MPD_TAG_MUSICBRAINZ_RELEASEGROUPID,
mpd_tag_type_MPD_TAG_MUSICBRAINZ_RELEASETRACKID, mpd_tag_type_MPD_TAG_MUSICBRAINZ_TRACKID,
mpd_tag_type_MPD_TAG_MUSICBRAINZ_WORKID, mpd_tag_type_MPD_TAG_NAME,
mpd_tag_type_MPD_TAG_ORIGINAL_DATE, mpd_tag_type_MPD_TAG_PERFORMER, mpd_tag_type_MPD_TAG_TITLE,
mpd_tag_type_MPD_TAG_TITLE_SORT, mpd_tag_type_MPD_TAG_TRACK, mpd_tag_type_MPD_TAG_UNKNOWN,
mpd_tag_type_MPD_TAG_WORK,
};
use crate::{
Connection,
error::{Error, Result},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Tag {
Artist = mpd_tag_type_MPD_TAG_ARTIST as isize,
Album = mpd_tag_type_MPD_TAG_ALBUM as isize,
AlbumArtist = mpd_tag_type_MPD_TAG_ALBUM_ARTIST as isize,
Title = mpd_tag_type_MPD_TAG_TITLE as isize,
Track = mpd_tag_type_MPD_TAG_TRACK as isize,
Name = mpd_tag_type_MPD_TAG_NAME as isize,
Genre = mpd_tag_type_MPD_TAG_GENRE as isize,
Date = mpd_tag_type_MPD_TAG_DATE as isize,
Composer = mpd_tag_type_MPD_TAG_COMPOSER as isize,
Performer = mpd_tag_type_MPD_TAG_PERFORMER as isize,
Comment = mpd_tag_type_MPD_TAG_COMMENT as isize,
Disc = mpd_tag_type_MPD_TAG_DISC as isize,
MusicbrainzArtistid = mpd_tag_type_MPD_TAG_MUSICBRAINZ_ARTISTID as isize,
MusicbrainzAlbumid = mpd_tag_type_MPD_TAG_MUSICBRAINZ_ALBUMID as isize,
MusicbrainzAlbumartistid = mpd_tag_type_MPD_TAG_MUSICBRAINZ_ALBUMARTISTID as isize,
MusicbrainzTrackid = mpd_tag_type_MPD_TAG_MUSICBRAINZ_TRACKID as isize,
MusicbrainzReleasetrackid = mpd_tag_type_MPD_TAG_MUSICBRAINZ_RELEASETRACKID as isize,
OriginalDate = mpd_tag_type_MPD_TAG_ORIGINAL_DATE as isize,
ArtistSort = mpd_tag_type_MPD_TAG_ARTIST_SORT as isize,
AlbumArtistSort = mpd_tag_type_MPD_TAG_ALBUM_ARTIST_SORT as isize,
Albumsort = mpd_tag_type_MPD_TAG_ALBUM_SORT as isize,
Label = mpd_tag_type_MPD_TAG_LABEL as isize,
MusicbrainzWorkid = mpd_tag_type_MPD_TAG_MUSICBRAINZ_WORKID as isize,
Grouping = mpd_tag_type_MPD_TAG_GROUPING as isize,
Work = mpd_tag_type_MPD_TAG_WORK as isize,
Conductor = mpd_tag_type_MPD_TAG_CONDUCTOR as isize,
ComposerSort = mpd_tag_type_MPD_TAG_COMPOSER_SORT as isize,
Ensemble = mpd_tag_type_MPD_TAG_ENSEMBLE as isize,
Movement = mpd_tag_type_MPD_TAG_MOVEMENT as isize,
Movementnumber = mpd_tag_type_MPD_TAG_MOVEMENTNUMBER as isize,
Location = mpd_tag_type_MPD_TAG_LOCATION as isize,
Mood = mpd_tag_type_MPD_TAG_MOOD as isize,
TitleSort = mpd_tag_type_MPD_TAG_TITLE_SORT as isize,
MusicbrainzReleasegroupid = mpd_tag_type_MPD_TAG_MUSICBRAINZ_RELEASEGROUPID as isize,
}
impl Tag {
#[must_use]
pub fn name(&self) -> String {
unsafe {
let name = mpd_tag_name(*self as i32);
if name.is_null() {
unreachable!("All possible tag inputs should are valid");
}
CStr::from_ptr(name).to_string_lossy().to_string()
}
}
pub fn parse(value: &str) -> Result<Self> {
let tag = unsafe { mpd_tag_name_iparse(CString::new(value)?.as_ptr()) };
#[allow(non_upper_case_globals)]
match tag {
mpd_tag_type_MPD_TAG_UNKNOWN => Err(Error::Unknown("Tag".to_string())),
mpd_tag_type_MPD_TAG_ARTIST => Ok(Self::Artist),
mpd_tag_type_MPD_TAG_ALBUM => Ok(Self::Album),
mpd_tag_type_MPD_TAG_ALBUM_ARTIST => Ok(Self::AlbumArtist),
mpd_tag_type_MPD_TAG_TITLE => Ok(Self::Title),
mpd_tag_type_MPD_TAG_TRACK => Ok(Self::Track),
mpd_tag_type_MPD_TAG_NAME => Ok(Self::Name),
mpd_tag_type_MPD_TAG_GENRE => Ok(Self::Genre),
mpd_tag_type_MPD_TAG_DATE => Ok(Self::Date),
mpd_tag_type_MPD_TAG_COMPOSER => Ok(Self::Composer),
mpd_tag_type_MPD_TAG_PERFORMER => Ok(Self::Performer),
mpd_tag_type_MPD_TAG_COMMENT => Ok(Self::Comment),
mpd_tag_type_MPD_TAG_DISC => Ok(Self::Disc),
mpd_tag_type_MPD_TAG_MUSICBRAINZ_ARTISTID => Ok(Self::MusicbrainzArtistid),
mpd_tag_type_MPD_TAG_MUSICBRAINZ_ALBUMID => Ok(Self::MusicbrainzAlbumid),
mpd_tag_type_MPD_TAG_MUSICBRAINZ_ALBUMARTISTID => Ok(Self::MusicbrainzAlbumartistid),
mpd_tag_type_MPD_TAG_MUSICBRAINZ_TRACKID => Ok(Self::MusicbrainzTrackid),
mpd_tag_type_MPD_TAG_MUSICBRAINZ_RELEASETRACKID => Ok(Self::MusicbrainzReleasetrackid),
mpd_tag_type_MPD_TAG_ORIGINAL_DATE => Ok(Self::OriginalDate),
mpd_tag_type_MPD_TAG_ARTIST_SORT => Ok(Self::ArtistSort),
mpd_tag_type_MPD_TAG_ALBUM_ARTIST_SORT => Ok(Self::AlbumArtistSort),
mpd_tag_type_MPD_TAG_ALBUM_SORT => Ok(Self::Albumsort),
mpd_tag_type_MPD_TAG_LABEL => Ok(Self::Label),
mpd_tag_type_MPD_TAG_MUSICBRAINZ_WORKID => Ok(Self::MusicbrainzWorkid),
mpd_tag_type_MPD_TAG_GROUPING => Ok(Self::Grouping),
mpd_tag_type_MPD_TAG_WORK => Ok(Self::Work),
mpd_tag_type_MPD_TAG_CONDUCTOR => Ok(Self::Conductor),
mpd_tag_type_MPD_TAG_COMPOSER_SORT => Ok(Self::ComposerSort),
mpd_tag_type_MPD_TAG_ENSEMBLE => Ok(Self::Ensemble),
mpd_tag_type_MPD_TAG_MOVEMENT => Ok(Self::Movement),
mpd_tag_type_MPD_TAG_MOVEMENTNUMBER => Ok(Self::Movementnumber),
mpd_tag_type_MPD_TAG_LOCATION => Ok(Self::Location),
mpd_tag_type_MPD_TAG_MOOD => Ok(Self::Mood),
mpd_tag_type_MPD_TAG_TITLE_SORT => Ok(Self::TitleSort),
mpd_tag_type_MPD_TAG_MUSICBRAINZ_RELEASEGROUPID => Ok(Self::MusicbrainzReleasegroupid),
_ => unreachable!(),
}
}
pub(super) fn receive(&self, connection: &Connection) -> Result<Option<String>> {
unsafe {
let pair = connection
.get_error(|| mpd_recv_pair_tag(connection.connection(), *self as i32))?;
Ok(if pair.is_null() {
None
} else {
let value = CStr::from_ptr((*pair).value).to_string_lossy().to_string();
mpd_return_pair(connection.connection(), pair);
Some(value)
})
}
}
}
#[cfg(test)]
mod tests {
use crate::Tag;
#[test]
fn name() {
assert_eq!(Tag::Composer.name(), "Composer");
}
#[test]
fn from() -> eyre::Result<()> {
assert_eq!(Tag::parse("composer")?, Tag::Composer);
Ok(())
}
#[test]
#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: Unknown(\"Tag\")")]
fn from_error() {
Tag::parse("aaa").unwrap();
}
}