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}