Skip to main content

mpris_server/
track_id.rs

1use std::{fmt, ops};
2
3use serde::{Deserialize, Deserializer, Serialize, de};
4use zbus::zvariant::{Basic, Type};
5use zbus::{ObjectPath, Variant};
6
7/// Unique track identifier.
8///
9/// If the media player implements the TrackList interface and allows
10/// the same track to appear multiple times in the tracklist, this
11/// must be unique within the scope of the tracklist.
12///
13/// Note that this should be a valid D-Bus object id, although clients
14/// should not assume that any object is actually exported with any
15/// interfaces at that path.
16///
17/// Media players may not use any paths starting with /org/mpris unless
18/// explicitly allowed by this specification. Such paths are intended to
19/// have special meaning, such as /org/mpris/MediaPlayer2/TrackList/NoTrack
20/// to indicate "no track".
21///
22/// <details><summary>Rationale</summary>
23///
24/// This is a D-Bus object id as that is the definitive way to have unique
25/// identifiers on D-Bus. It also allows for future optional expansions
26/// to the specification where tracks are exported to D-Bus with an
27/// interface similar to `org.gnome.UPnP.MediaItem2`.
28///
29/// </details>
30#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Type)]
31#[serde(transparent)]
32#[doc(alias = "Track_Id")]
33pub struct TrackId(ObjectPath<'static>);
34
35impl TrackId {
36    /// A special track ID to indicate "no track".
37    pub const NO_TRACK: TrackId = TrackId(ObjectPath::from_static_str_unchecked(
38        "/org/mpris/MediaPlayer2/TrackList/NoTrack",
39    ));
40
41    /// Returns the track ID as an [`ObjectPath`].
42    pub fn into_inner(self) -> ObjectPath<'static> {
43        self.0
44    }
45}
46
47impl Basic for TrackId {
48    const SIGNATURE_CHAR: char = ObjectPath::SIGNATURE_CHAR;
49    const SIGNATURE_STR: &'static str = ObjectPath::SIGNATURE_STR;
50
51    fn alignment() -> usize {
52        ObjectPath::alignment()
53    }
54}
55
56impl ops::Deref for TrackId {
57    type Target = ObjectPath<'static>;
58
59    fn deref(&self) -> &Self::Target {
60        &self.0
61    }
62}
63
64impl From<TrackId> for ObjectPath<'static> {
65    fn from(o: TrackId) -> Self {
66        o.into_inner()
67    }
68}
69
70impl From<TrackId> for Variant<'_> {
71    fn from(o: TrackId) -> Self {
72        o.into_inner().into()
73    }
74}
75
76impl<'unowned, 'owned: 'unowned> From<&'owned TrackId> for ObjectPath<'unowned> {
77    fn from(o: &'owned TrackId) -> Self {
78        ObjectPath::from_str_unchecked(o.as_str())
79    }
80}
81
82impl<'a> From<ObjectPath<'a>> for TrackId {
83    fn from(o: ObjectPath<'a>) -> Self {
84        TrackId(o.into_owned())
85    }
86}
87
88impl TryFrom<&'_ str> for TrackId {
89    type Error = zbus::Error;
90
91    fn try_from(value: &str) -> Result<Self, Self::Error> {
92        Ok(Self::from(ObjectPath::try_from(value)?))
93    }
94}
95
96impl TryFrom<String> for TrackId {
97    type Error = zbus::Error;
98
99    fn try_from(value: String) -> Result<Self, Self::Error> {
100        Ok(Self::from(ObjectPath::try_from(value)?))
101    }
102}
103
104impl TryFrom<Variant<'_>> for TrackId {
105    type Error = zbus::Error;
106
107    fn try_from(value: Variant<'_>) -> Result<Self, Self::Error> {
108        ObjectPath::try_from(value).map(|o| Self(o.to_owned()))
109    }
110}
111
112impl TryFrom<&Variant<'_>> for TrackId {
113    type Error = zbus::Error;
114
115    fn try_from(value: &Variant<'_>) -> Result<Self, Self::Error> {
116        ObjectPath::try_from(value).map(|o| Self(o.to_owned()))
117    }
118}
119
120impl<'de> Deserialize<'de> for TrackId {
121    fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
122    where
123        D: Deserializer<'de>,
124    {
125        String::deserialize(deserializer)
126            .and_then(|s| ObjectPath::try_from(s).map_err(|e| de::Error::custom(e.to_string())))
127            .map(Self)
128    }
129}
130
131impl fmt::Display for TrackId {
132    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133        fmt::Display::fmt(&self.as_str(), f)
134    }
135}