1use std::{fmt, ops};
23use serde::{de, Deserialize, Deserializer, Serialize};
4use zbus::zvariant::{serialized::Format, Basic, Error, ObjectPath, Result, Type, Value};
56/// Unique track identifier.
7///
8/// If the media player implements the TrackList interface and allows
9/// the same track to appear multiple times in the tracklist, this
10/// must be unique within the scope of the tracklist.
11///
12/// Note that this should be a valid D-Bus object id, although clients
13/// should not assume that any object is actually exported with any
14/// interfaces at that path.
15///
16/// Media players may not use any paths starting with /org/mpris unless
17/// explicitly allowed by this specification. Such paths are intended to
18/// have special meaning, such as /org/mpris/MediaPlayer2/TrackList/NoTrack
19/// to indicate "no track".
20///
21/// <details><summary>Rationale</summary>
22///
23/// This is a D-Bus object id as that is the definitive way to have unique
24/// identifiers on D-Bus. It also allows for future optional expansions
25/// to the specification where tracks are exported to D-Bus with an
26/// interface similar to `org.gnome.UPnP.MediaItem2`.
27///
28/// </details>
29#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Serialize, Type)]
30#[serde(transparent)]
31#[doc(alias = "Track_Id")]
32pub struct TrackId(ObjectPath<'static>);
3334impl TrackId {
35/// A special track ID to indicate "no track".
36pub const NO_TRACK: TrackId = TrackId(ObjectPath::from_static_str_unchecked(
37"/org/mpris/MediaPlayer2/TrackList/NoTrack",
38 ));
3940/// Returns the track ID as an [`ObjectPath`].
41pub fn into_inner(self) -> ObjectPath<'static> {
42self.0
43}
44}
4546impl Basic for TrackId {
47const SIGNATURE_CHAR: char = ObjectPath::SIGNATURE_CHAR;
48const SIGNATURE_STR: &'static str = ObjectPath::SIGNATURE_STR;
4950fn alignment(format: Format) -> usize {
51 ObjectPath::alignment(format)
52 }
53}
5455impl ops::Dereffor TrackId {
56type Target = ObjectPath<'static>;
5758fn deref(&self) -> &Self::Target {
59&self.0
60}
61}
6263impl From<TrackId> for ObjectPath<'static> {
64fn from(o: TrackId) -> Self {
65o.into_inner()
66 }
67}
6869impl From<TrackId> for Value<'_> {
70fn from(o: TrackId) -> Self {
71o.into_inner().into()
72 }
73}
7475impl<'unowned, 'owned: 'unowned> From<&'owned TrackId> for ObjectPath<'unowned> {
76fn from(o: &'owned TrackId) -> Self {
77 ObjectPath::from_str_unchecked(o.as_str())
78 }
79}
8081impl<'a> From<ObjectPath<'a>> for TrackId {
82fn from(o: ObjectPath<'a>) -> Self {
83TrackId(o.into_owned())
84 }
85}
8687impl TryFrom<&'_ str> for TrackId {
88type Error = Error;
8990fn try_from(value: &str) -> Result<Self> {
91Ok(Self::from(ObjectPath::try_from(value)?))
92 }
93}
9495impl TryFrom<String> for TrackId {
96type Error = Error;
9798fn try_from(value: String) -> Result<Self> {
99Ok(Self::from(ObjectPath::try_from(value)?))
100 }
101}
102103impl TryFrom<Value<'_>> for TrackId {
104type Error = Error;
105106fn try_from(value: Value<'_>) -> Result<Self> {
107ObjectPath::try_from(value).map(|o| Self(o.to_owned()))
108 }
109}
110111impl TryFrom<&Value<'_>> for TrackId {
112type Error = Error;
113114fn try_from(value: &Value<'_>) -> Result<Self> {
115ObjectPath::try_from(value).map(|o| Self(o.to_owned()))
116 }
117}
118119impl<'de> Deserialize<'de> for TrackId {
120fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
121where
122D: Deserializer<'de>,
123 {
124String::deserialize(deserializer)
125 .and_then(|s| ObjectPath::try_from(s).map_err(|e| de::Error::custom(e.to_string())))
126 .map(Self)
127 }
128}
129130impl fmt::Displayfor TrackId {
131fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
132fmt::Display::fmt(&self.as_str(), f)
133 }
134}