sdp_rs/lines/
repeat.rs

1//! Types related to the repeat line (`r=`).
2
3use crate::Error;
4use std::convert::{TryFrom, TryInto};
5
6/// The repeat line (`r=`) tokenizer. This is low level stuff and you shouldn't interact directly
7/// with it, unless you know what you are doing.
8pub use crate::tokenizers::time::repeat::Tokenizer;
9
10/// The repeat line (`r=`) of SDP.
11use crate::lines::common::TypedTime;
12
13/// The repeat time (`r=`) of SDP.
14#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Clone)]
15pub struct Repeat {
16    pub interval: TypedTime,
17    pub duration: TypedTime,
18    pub offsets: Vec<TypedTime>,
19}
20
21impl<'a> TryFrom<Tokenizer<'a>> for Repeat {
22    type Error = Error;
23
24    fn try_from(tokenizer: Tokenizer<'a>) -> Result<Self, Self::Error> {
25        Ok(Self {
26            interval: tokenizer.interval.try_into().map_err(|e| {
27                Self::Error::parser_with_error("repeat interval", tokenizer.interval, e)
28            })?,
29            duration: tokenizer.duration.try_into().map_err(|e| {
30                Self::Error::parser_with_error("repeat duration", tokenizer.duration, e)
31            })?,
32            offsets: tokenizer
33                .offsets
34                .into_iter()
35                .map(TryInto::<TypedTime>::try_into)
36                .collect::<Result<Vec<_>, Error>>()?,
37        })
38    }
39}
40
41impl std::fmt::Display for Repeat {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        write!(
44            f,
45            "r={} {} {}",
46            self.interval,
47            self.duration,
48            self.offsets
49                .iter()
50                .map(|i| i.to_string())
51                .collect::<Vec<_>>()
52                .join(" ")
53        )
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60    use chrono::Duration;
61
62    #[test]
63    fn from_tokenizer1() {
64        let tokenizer: Tokenizer = ("604800", "3600", vec!["0", "90000"]).into();
65
66        assert_eq!(
67            Repeat::try_from(tokenizer),
68            Ok(Repeat {
69                interval: TypedTime::None(Duration::seconds(604800)),
70                duration: TypedTime::None(Duration::seconds(3600)),
71                offsets: vec![
72                    TypedTime::None(Duration::seconds(0)),
73                    TypedTime::None(Duration::seconds(90000))
74                ]
75            })
76        );
77    }
78
79    #[test]
80    fn from_tokenizer2() {
81        let tokenizer: Tokenizer = ("7d", "1h", vec!["0", "25h"]).into();
82
83        assert_eq!(
84            Repeat::try_from(tokenizer),
85            Ok(Repeat {
86                interval: TypedTime::Days(Duration::seconds(604800)),
87                duration: TypedTime::Hours(Duration::seconds(3600)),
88                offsets: vec![
89                    TypedTime::None(Duration::seconds(0)),
90                    TypedTime::Hours(Duration::seconds(90000))
91                ]
92            })
93        );
94    }
95
96    #[test]
97    fn display1() {
98        let repeat = Repeat {
99            interval: TypedTime::Days(Duration::seconds(604800)),
100            duration: TypedTime::Hours(Duration::seconds(3600)),
101            offsets: vec![
102                TypedTime::None(Duration::seconds(0)),
103                TypedTime::Hours(Duration::seconds(90000)),
104            ],
105        };
106
107        assert_eq!(repeat.to_string(), "r=7d 1h 0 25h");
108    }
109
110    #[test]
111    fn display2() {
112        let repeat = Repeat {
113            interval: TypedTime::None(Duration::seconds(604800)),
114            duration: TypedTime::None(Duration::seconds(3600)),
115            offsets: vec![
116                TypedTime::None(Duration::seconds(0)),
117                TypedTime::None(Duration::seconds(90000)),
118            ],
119        };
120
121        assert_eq!(repeat.to_string(), "r=604800 3600 0 90000");
122    }
123}