Skip to main content

doobs_mpris/types/
playback_status.rs

1use std::fmt::{self, Display};
2use std::str::FromStr;
3
4use serde::{Deserialize, Serialize};
5use zvariant::{OwnedValue, Type, Value};
6
7use crate::{Error, Result};
8
9/// A playback state.
10#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
11pub enum PlaybackStatus {
12    /// A track is currently playing.
13    Playing,
14    /// A track is currently paused.
15    Paused,
16    /// There is no track currently playing.
17    Stopped,
18}
19
20impl FromStr for PlaybackStatus {
21    type Err = Error;
22
23    fn from_str(s: &str) -> Result<Self> {
24        match s.to_lowercase().trim() {
25            "playing" => Ok(Self::Playing),
26            "paused" => Ok(Self::Paused),
27            "stopped" => Ok(Self::Stopped),
28            _ => Err(Error::InvalidEnum {
29                got: s.to_string(),
30                expected: &["Playing", "Paused", "Stopped"],
31            }),
32        }
33    }
34}
35
36impl Display for PlaybackStatus {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        write!(
39            f,
40            "{}",
41            match self {
42                Self::Playing => "Playing",
43                Self::Paused => "Paused",
44                Self::Stopped => "Stopped",
45            }
46        )
47    }
48}
49
50// traits necessary to use it as a type in zbus
51
52impl Type for PlaybackStatus {
53    const SIGNATURE: &'static zvariant::Signature = &zvariant::Signature::Str;
54}
55
56impl From<PlaybackStatus> for Value<'_> {
57    fn from(value: PlaybackStatus) -> Self {
58        Value::from(value.to_string())
59    }
60}
61
62impl TryFrom<Value<'_>> for PlaybackStatus {
63    type Error = zvariant::Error;
64
65    fn try_from(value: Value) -> std::result::Result<Self, Self::Error> {
66        let value: &str = value.downcast_ref::<&str>()?;
67        let value = PlaybackStatus::from_str(value)?;
68        Ok(value)
69    }
70}
71
72impl TryFrom<OwnedValue> for PlaybackStatus {
73    type Error = zvariant::Error;
74
75    fn try_from(value: OwnedValue) -> std::result::Result<Self, Self::Error> {
76        let value = value.downcast_ref::<&str>()?;
77        let value = PlaybackStatus::from_str(value)?;
78        Ok(value)
79    }
80}
81
82#[cfg(test)]
83mod test {
84    use zvariant::serialized::Context;
85    use zvariant::{LE, OwnedValue, Value, to_bytes};
86
87    use super::PlaybackStatus;
88
89    #[test]
90    fn success() {
91        let expected = PlaybackStatus::Paused;
92
93        // lowercase string works
94        let v = Value::Str("paused".into());
95        let status = PlaybackStatus::try_from(v.clone()).unwrap();
96
97        assert_eq!(status, expected);
98        assert_eq!(Value::Str("Paused".into()), Value::from(expected));
99
100        let ov = OwnedValue::try_from(v.clone()).unwrap();
101        let duration = PlaybackStatus::try_from(ov.clone()).unwrap();
102
103        assert_eq!(duration, expected);
104    }
105
106    #[test]
107    fn wrong_enum_type() {
108        let v = Value::Str("unknown".into());
109        let err = PlaybackStatus::try_from(v.clone()).unwrap_err();
110
111        assert!(matches!(err, zvariant::Error::Message(_)));
112
113        let ov = OwnedValue::try_from(v).unwrap();
114        let err = PlaybackStatus::try_from(ov).unwrap_err();
115
116        assert!(matches!(err, zvariant::Error::Message(_)));
117    }
118
119    #[test]
120    fn wrong_dbus_type() {
121        let v = Value::U64(5);
122        let err = PlaybackStatus::try_from(v.clone()).unwrap_err();
123
124        assert_eq!(zvariant::Error::IncorrectType, err);
125
126        let ov = OwnedValue::try_from(v).unwrap();
127        let err = PlaybackStatus::try_from(ov).unwrap_err();
128
129        assert_eq!(zvariant::Error::IncorrectType, err);
130    }
131
132    #[test]
133    fn serialize() {
134        let ctxt = Context::new_dbus(LE, 0);
135        let encoded = to_bytes(ctxt, &PlaybackStatus::Stopped).unwrap();
136        let decoded: &str = encoded.deserialize().unwrap().0;
137
138        assert_eq!(decoded, "Stopped");
139    }
140
141    #[test]
142    fn deserialize() {
143        let ctxt = Context::new_dbus(LE, 0);
144        let encoded = to_bytes(ctxt, "Stopped").unwrap();
145        let decoded: PlaybackStatus = encoded.deserialize().unwrap().0;
146
147        assert_eq!(decoded, PlaybackStatus::Stopped);
148    }
149}