use std::ffi::CStr;
use mpdclient_sys::{
mpd_idle_name, mpd_recv_idle, mpd_run_idle, mpd_run_idle_mask, mpd_run_noidle, mpd_send_idle,
mpd_send_idle_mask,
};
use crate::{Connection, error::Result};
pub struct Idle<'a> {
connection: &'a Connection,
}
impl<'a> Idle<'a> {
pub(crate) fn new(connection: &'a Connection) -> Self {
Self { connection }
}
#[doc(alias = "mpd_run_idle")]
pub fn idle(&self) -> Result<Vec<IdleReturn>> {
let idle = self
.connection
.get_error(|| unsafe { mpd_run_idle(self.connection.connection()) })?;
Ok(IdleReturn::from_u32(idle))
}
#[doc(alias = "mpd_run_idle_mask")]
pub fn idle_mask(&self, mask: &[IdleReturn]) -> Result<Vec<IdleReturn>> {
let idle = self.connection.get_error(|| unsafe {
mpd_run_idle_mask(self.connection.connection(), IdleReturn::to_u32(mask))
})?;
Ok(IdleReturn::from_u32(idle))
}
#[doc(alias = "mpd_send_idle")]
pub fn set(&self) -> Result<()> {
self.connection
.get_bool_error(|| unsafe { mpd_send_idle(self.connection.connection()) })
}
#[doc(alias = "mpd_send_idle_mask")]
pub fn set_mask(&self, mask: &[IdleReturn]) -> Result<()> {
self.connection.get_bool_error(|| unsafe {
mpd_send_idle_mask(self.connection.connection(), IdleReturn::to_u32(mask))
})
}
#[doc(alias = "mpd_send_noidle", alias = "mpd_run_noidle")]
pub fn unset(&self) -> Result<Vec<IdleReturn>> {
let idle = self
.connection
.get_error(|| unsafe { mpd_run_noidle(self.connection.connection()) })?;
Ok(IdleReturn::from_u32(idle))
}
#[doc(alias = "mpd_recv_idle")]
pub fn receive(&self, disable_timeout: bool) -> Result<Vec<IdleReturn>> {
let idle = self.connection.get_error(|| unsafe {
mpd_recv_idle(self.connection.connection(), disable_timeout)
})?;
Ok(IdleReturn::from_u32(idle))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IdleReturn {
Database = 0x1,
StoredPlaylist = 0x2,
Queue = 0x4,
Player = 0x8,
Mixer = 0x10,
Output = 0x20,
Options = 0x40,
Update = 0x80,
Sticker = 0x100,
Subscription = 0x200,
Message = 0x400,
Partition = 0x800,
Neighbor = 0x1000,
Mount = 0x2000,
}
impl IdleReturn {
fn from_u32(value: u32) -> Vec<Self> {
let mut ret: Vec<Self> = Vec::new();
Self::check_value(&mut ret, value, Self::Database);
Self::check_value(&mut ret, value, Self::StoredPlaylist);
Self::check_value(&mut ret, value, Self::Queue);
Self::check_value(&mut ret, value, Self::Player);
Self::check_value(&mut ret, value, Self::Mixer);
Self::check_value(&mut ret, value, Self::Output);
Self::check_value(&mut ret, value, Self::Options);
Self::check_value(&mut ret, value, Self::Update);
Self::check_value(&mut ret, value, Self::Sticker);
Self::check_value(&mut ret, value, Self::Subscription);
Self::check_value(&mut ret, value, Self::Message);
Self::check_value(&mut ret, value, Self::Partition);
Self::check_value(&mut ret, value, Self::Neighbor);
Self::check_value(&mut ret, value, Self::Mount);
ret
}
fn check_value(vec: &mut Vec<Self>, value: u32, idle: IdleReturn) {
if value & idle as u32 != 0 {
vec.push(idle);
}
}
fn to_u32(value: &[Self]) -> u32 {
let mut ret = 0;
for v in value {
ret |= *v as u32;
}
ret
}
#[must_use]
pub fn name(&self) -> String {
unsafe {
CStr::from_ptr(mpd_idle_name(*self as u32))
.to_string_lossy()
.to_string()
}
}
}
#[cfg(test)]
mod tests {
use crate::connection::idle::IdleReturn;
#[test]
fn idle_return_single_database() {
assert_eq!(IdleReturn::from_u32(0b1), vec![IdleReturn::Database]);
}
#[test]
fn idle_return_single_queue() {
assert_eq!(IdleReturn::from_u32(0b100), vec![IdleReturn::Queue]);
}
#[test]
fn idle_return_single_mixer() {
assert_eq!(IdleReturn::from_u32(0b10000), vec![IdleReturn::Mixer]);
}
#[test]
fn idle_return_multiple_sp_p() {
assert_eq!(
IdleReturn::from_u32(0b1010),
vec![IdleReturn::StoredPlaylist, IdleReturn::Player]
);
}
#[test]
fn idle_return_multiple_o_o() {
assert_eq!(
IdleReturn::from_u32(0b110_0000),
vec![IdleReturn::Output, IdleReturn::Options]
);
}
#[test]
fn idle_to_u32_database() {
assert_eq!(IdleReturn::to_u32(&[IdleReturn::Database]), 0b1);
}
#[test]
fn idle_to_u32_queue() {
assert_eq!(IdleReturn::to_u32(&[IdleReturn::Queue]), 0b100);
}
#[test]
fn idle_to_mixer() {
assert_eq!(IdleReturn::to_u32(&[IdleReturn::Mixer]), 0b10000);
}
#[test]
fn idle_to_sp_p() {
assert_eq!(
IdleReturn::to_u32(&[IdleReturn::StoredPlaylist, IdleReturn::Player]),
0b1010
);
}
#[test]
fn idle_to_o_o() {
assert_eq!(
IdleReturn::to_u32(&[IdleReturn::Output, IdleReturn::Options]),
0b110_0000
);
}
}