1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Copyright (c) 2019 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
use crate::core::{FromXml, IntoXml};
use crate::ns::TUNE;
use crate::pubsub::PubSubPayload;

/// Container for formatted text.
#[derive(FromXml, IntoXml, Debug, PartialEq, Clone, Default)]
#[xml(namespace = TUNE, name = "tune")]
pub struct Tune {
    /// The artist or performer of the song or piece.
    #[xml(child(namespace = TUNE, name = "artist", extract(text), default))]
    artist: Option<String>,

    /// The duration of the song or piece in seconds.
    #[xml(child(namespace = TUNE, name = "length", extract(text(type = u16)), default))]
    length: Option<u16>,

    /// The user's rating of the song or piece, from 1 (lowest) to 10 (highest).
    #[xml(child(namespace = TUNE, name = "rating", extract(text(type = u8)), default))]
    rating: Option<u8>,

    /// The collection (e.g., album) or other source (e.g., a band website that hosts streams or
    /// audio files).
    #[xml(child(namespace = TUNE, name = "source", extract(text), default))]
    source: Option<String>,

    /// The title of the song or piece.
    #[xml(child(namespace = TUNE, name = "title", extract(text), default))]
    title: Option<String>,

    /// A unique identifier for the tune; e.g., the track number within a collection or the
    /// specific URI for the object (e.g., a stream or audio file).
    #[xml(child(namespace = TUNE, name = "track", extract(text), default))]
    track: Option<String>,

    /// A URI or URL pointing to information about the song, collection, or artist.
    #[xml(child(namespace = TUNE, name = "uri", extract(text), default))]
    uri: Option<String>,
}

impl PubSubPayload for Tune {}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::Element;

    #[cfg(target_pointer_width = "32")]
    #[test]
    fn test_size() {
        assert_size!(Tune, 68);
    }

    #[cfg(target_pointer_width = "64")]
    #[test]
    fn test_size() {
        assert_size!(Tune, 128);
    }

    #[test]
    fn empty() {
        let elem: Element = "<tune xmlns='http://jabber.org/protocol/tune'/>"
            .parse()
            .unwrap();
        let elem2 = elem.clone();
        let tune = Tune::try_from(elem).unwrap();
        assert!(tune.artist.is_none());
        assert!(tune.length.is_none());
        assert!(tune.rating.is_none());
        assert!(tune.source.is_none());
        assert!(tune.title.is_none());
        assert!(tune.track.is_none());
        assert!(tune.uri.is_none());

        let elem3 = tune.into();
        assert_eq!(elem2, elem3);
    }

    #[test]
    fn full() {
        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>"
            .parse()
            .unwrap();
        let tune = Tune::try_from(elem).unwrap();
        assert_eq!(tune.artist, Some(String::from("Yes")));
        assert_eq!(tune.length, Some(686));
        assert_eq!(tune.rating, Some(8));
        assert_eq!(tune.source, Some(String::from("Yessongs")));
        assert_eq!(tune.title, Some(String::from("Heart of the Sunrise")));
        assert_eq!(tune.track, Some(String::from("3")));
        assert_eq!(
            tune.uri,
            Some(String::from(
                "http://www.yesworld.com/lyrics/Fragile.html#9"
            ))
        );
    }
}