xmpp_parsers/
tune.rs

1// Copyright (c) 2019 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7use xso::{AsXml, FromXml};
8
9use crate::ns;
10use crate::pubsub::PubSubPayload;
11
12generate_elem_id!(
13    /// The artist or performer of the song or piece.
14    Artist,
15    "artist",
16    TUNE
17);
18
19generate_elem_id!(
20    /// The duration of the song or piece in seconds.
21    Length,
22    "length",
23    TUNE,
24    u16
25);
26
27generate_elem_id!(
28    /// The user's rating of the song or piece, from 1 (lowest) to 10 (highest).
29    Rating,
30    "rating",
31    TUNE,
32    u8
33);
34
35generate_elem_id!(
36    /// The collection (e.g., album) or other source (e.g., a band website that hosts streams or
37    /// audio files).
38    Source,
39    "source",
40    TUNE
41);
42
43generate_elem_id!(
44    /// The title of the song or piece.
45    Title,
46    "title",
47    TUNE
48);
49
50generate_elem_id!(
51    /// A unique identifier for the tune; e.g., the track number within a collection or the
52    /// specific URI for the object (e.g., a stream or audio file).
53    Track,
54    "track",
55    TUNE
56);
57
58generate_elem_id!(
59    /// A URI or URL pointing to information about the song, collection, or artist.
60    Uri,
61    "uri",
62    TUNE
63);
64
65/// Container for formatted text.
66#[derive(FromXml, AsXml, Debug, Clone, PartialEq)]
67#[xml(namespace = ns::TUNE, name = "tune")]
68pub struct Tune {
69    /// The artist or performer of the song or piece.
70    #[xml(child(default))]
71    artist: Option<Artist>,
72
73    /// The duration of the song or piece in seconds.
74    #[xml(child(default))]
75    length: Option<Length>,
76
77    /// The user's rating of the song or piece, from 1 (lowest) to 10 (highest).
78    #[xml(child(default))]
79    rating: Option<Rating>,
80
81    /// The collection (e.g., album) or other source (e.g., a band website that hosts streams or
82    /// audio files).
83    #[xml(child(default))]
84    source: Option<Source>,
85
86    /// The title of the song or piece.
87    #[xml(child(default))]
88    title: Option<Title>,
89
90    /// A unique identifier for the tune; e.g., the track number within a collection or the
91    /// specific URI for the object (e.g., a stream or audio file).
92    #[xml(child(default))]
93    track: Option<Track>,
94
95    /// A URI or URL pointing to information about the song, collection, or artist.
96    #[xml(child(default))]
97    uri: Option<Uri>,
98}
99
100impl PubSubPayload for Tune {}
101
102impl Tune {
103    /// Construct an empty `<tune/>` element.
104    pub fn new() -> Tune {
105        Tune {
106            artist: None,
107            length: None,
108            rating: None,
109            source: None,
110            title: None,
111            track: None,
112            uri: None,
113        }
114    }
115}
116
117impl Default for Tune {
118    fn default() -> Self {
119        Self::new()
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126    use core::str::FromStr;
127    use minidom::Element;
128
129    #[cfg(target_pointer_width = "32")]
130    #[test]
131    fn test_size() {
132        assert_size!(Tune, 68);
133        assert_size!(Artist, 12);
134        assert_size!(Length, 2);
135        assert_size!(Rating, 1);
136        assert_size!(Source, 12);
137        assert_size!(Title, 12);
138        assert_size!(Track, 12);
139        assert_size!(Uri, 12);
140    }
141
142    #[cfg(target_pointer_width = "64")]
143    #[test]
144    fn test_size() {
145        assert_size!(Tune, 128);
146        assert_size!(Artist, 24);
147        assert_size!(Length, 2);
148        assert_size!(Rating, 1);
149        assert_size!(Source, 24);
150        assert_size!(Title, 24);
151        assert_size!(Track, 24);
152        assert_size!(Uri, 24);
153    }
154
155    #[test]
156    fn empty() {
157        let elem: Element = "<tune xmlns='http://jabber.org/protocol/tune'/>"
158            .parse()
159            .unwrap();
160        let elem2 = elem.clone();
161        let tune = Tune::try_from(elem).unwrap();
162        assert!(tune.artist.is_none());
163        assert!(tune.length.is_none());
164        assert!(tune.rating.is_none());
165        assert!(tune.source.is_none());
166        assert!(tune.title.is_none());
167        assert!(tune.track.is_none());
168        assert!(tune.uri.is_none());
169
170        let elem3 = tune.into();
171        assert_eq!(elem2, elem3);
172    }
173
174    #[test]
175    fn full() {
176        let elem: Element = "<tune xmlns='http://jabber.org/protocol/tune'><artist>Yes</artist><length>686</length><rating>8</rating><source>Yessongs</source><title>Heart of the Sunrise</title><track>3</track><uri>http://www.yesworld.com/lyrics/Fragile.html#9</uri></tune>"
177            .parse()
178            .unwrap();
179        let tune = Tune::try_from(elem).unwrap();
180        assert_eq!(tune.artist, Some(Artist::from_str("Yes").unwrap()));
181        assert_eq!(tune.length, Some(Length(686)));
182        assert_eq!(tune.rating, Some(Rating(8)));
183        assert_eq!(tune.source, Some(Source::from_str("Yessongs").unwrap()));
184        assert_eq!(
185            tune.title,
186            Some(Title::from_str("Heart of the Sunrise").unwrap())
187        );
188        assert_eq!(tune.track, Some(Track::from_str("3").unwrap()));
189        assert_eq!(
190            tune.uri,
191            Some(Uri::from_str("http://www.yesworld.com/lyrics/Fragile.html#9").unwrap())
192        );
193    }
194}