mpdclient 0.2.0

Rust interface to MPD using libmpdclient
Documentation
use crate::{Connection, Error, error::Result};
pub use directory::Directory;
use mpdclient_sys::{
    mpd_entity_get_directory, mpd_entity_get_playlist, mpd_entity_get_song, mpd_entity_get_type,
    mpd_entity_type_MPD_ENTITY_TYPE_DIRECTORY, mpd_entity_type_MPD_ENTITY_TYPE_PLAYLIST,
    mpd_entity_type_MPD_ENTITY_TYPE_SONG, mpd_entity_type_MPD_ENTITY_TYPE_UNKNOWN, mpd_recv_entity,
};
pub use playlist::Playlist;
pub use song::Song;

/// Directory struct returned as an [`Entity`]
pub mod directory;

/// Playlist struct returned as an [`Entity`]
pub mod playlist;

/// Song struct returned as an [`Entity`]
pub mod song;

/// Collective entity type.
///
/// Mostly used as a intermediate before being unwrapped to a [`Directory`], [`Song`] or
/// [`Playlist`].
///
/// Also used as a return if requesting the complete database.
#[derive(Debug)]
pub enum Entity {
    /// Directory which can contain more entities.
    Directory(Directory),

    /// Song file, can be added to a playlist or the queue.
    Song(Song),

    /// Basic information of a stored playlist.
    Playlist(Playlist),
}

/// Iterator to get entities ready to be received from MPD.
#[derive(Debug)]
pub struct EntityReceiver<'a> {
    connection: &'a Connection,
}

impl<'a> EntityReceiver<'a> {
    /// Creates a new [`EntityReceiver`].
    pub(super) fn new(connection: &'a Connection) -> Self {
        Self { connection }
    }

    /// Receives all entities as `Vec`, wrapping them in one `Result`.
    ///
    /// # Errors
    ///
    /// This function will return an [`Error::Mpd`] if one or more of the
    /// receive requests returned an error.
    pub fn receive_all(self) -> Result<Vec<Entity>> {
        self.collect()
    }
}

impl Iterator for EntityReceiver<'_> {
    type Item = Result<Entity>;

    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            let entity = self
                .connection
                .get_error(|| mpd_recv_entity(self.connection.connection()));
            let entity = match entity {
                Ok(entity) => entity,
                Err(err) => return Some(Err(err)),
            };
            if entity.is_null() {
                return None;
            }

            let entity_type = mpd_entity_get_type(entity);
            #[allow(non_upper_case_globals)]
            match entity_type {
                mpd_entity_type_MPD_ENTITY_TYPE_UNKNOWN => {
                    Some(Err(Error::Unknown("Entity".to_string())))
                }
                mpd_entity_type_MPD_ENTITY_TYPE_DIRECTORY => {
                    let dir = mpd_entity_get_directory(entity);
                    Some(Ok(Entity::Directory(Directory::new(dir.cast_mut()))))
                }
                mpd_entity_type_MPD_ENTITY_TYPE_SONG => {
                    let song = mpd_entity_get_song(entity);
                    Some(Ok(Entity::Song(Song::new(song.cast_mut()))))
                }
                mpd_entity_type_MPD_ENTITY_TYPE_PLAYLIST => {
                    let playlist = mpd_entity_get_playlist(entity);
                    Some(Ok(Entity::Playlist(Playlist::new(playlist.cast_mut()))))
                }
                _ => unreachable!(),
            }
        }
    }
}