mpdclient 0.2.0

Rust interface to MPD using libmpdclient
Documentation
use std::{
    ffi::CStr,
    path::PathBuf,
    time::{Duration, SystemTime, UNIX_EPOCH},
};

use mpdclient_sys::{
    mpd_playlist, mpd_playlist_get_last_modified, mpd_playlist_get_path, mpd_recv_playlist,
};

use crate::{Connection, error::Result};

/// Basic information of a playlist in the MPD database.
#[derive(Debug)]
pub struct Playlist {
    inner: *mut mpd_playlist,
}

impl Playlist {
    pub(super) fn new(mpd_playlist: *mut mpd_playlist) -> Self {
        Self {
            inner: mpd_playlist,
        }
    }

    /// Returns the path in the database of MPD.
    #[must_use]
    pub fn path(&self) -> PathBuf {
        let path = unsafe {
            let ptr = mpd_playlist_get_path(self.inner);
            CStr::from_ptr(ptr).to_string_lossy().to_string()
        };
        PathBuf::from(path)
    }

    /// Returns the time the playlist was last modified.
    // allow because it should be correct in the c library
    #[allow(clippy::cast_sign_loss)]
    #[must_use]
    pub fn last_modified(&self) -> Option<SystemTime> {
        let time = unsafe { mpd_playlist_get_last_modified(self.inner) };
        if time == 0 {
            None
        } else {
            Some(UNIX_EPOCH + Duration::from_secs(time as u64))
        }
    }
}

unsafe impl Send for Playlist {}

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

impl<'a> PlaylistReceiver<'a> {
    pub(crate) fn new(connection: &'a Connection) -> Self {
        Self { connection }
    }

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

impl Iterator for PlaylistReceiver<'_> {
    type Item = Result<Playlist>;

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