1use crate::{
2 lines::{Active, Repeat, Zone},
3 Error,
4};
5use std::convert::{TryFrom, TryInto};
6
7pub use crate::tokenizers::time::Tokenizer;
12
13#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Clone)]
15pub struct Time {
16 pub active: Active,
17 pub repeat: Vec<Repeat>,
18 pub zone: Option<Zone>,
19}
20
21impl<'a> TryFrom<Tokenizer<'a>> for Time {
22 type Error = Error;
23
24 fn try_from(tokenizer: Tokenizer<'a>) -> Result<Self, Self::Error> {
25 Ok(Self {
26 active: tokenizer.active.try_into()?,
27 repeat: tokenizer
28 .repeat
29 .into_iter()
30 .map(TryInto::try_into)
31 .collect::<Result<Vec<_>, _>>()?,
32 zone: tokenizer.zone.map(TryInto::try_into).transpose()?,
33 })
34 }
35}
36
37impl std::fmt::Display for Time {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 write!(f, "{}", self.active)?;
40 for repeat in self.repeat.iter() {
41 write!(f, "\r\n{}", repeat)?
42 }
43 if let Some(zone) = &self.zone {
44 write!(f, "\r\n{}", zone)?
45 }
46
47 Ok(())
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use crate::lines::{common::TypedTime, zone::ZonePart};
55 use chrono::Duration;
56
57 #[test]
58 fn from_tokenizer1() {
59 let tokenizer = Tokenizer {
60 active: ("3724394400", "3724398000").into(),
61 repeat: vec![
62 ("604800", "3600", vec!["0"]).into(),
63 ("7d", "1h", vec!["0", "25h"]).into(),
64 ],
65 zone: Some(vec![("3730928400", "-1h"), ("3749680800", "0")].into()),
66 };
67
68 assert_eq!(
69 Time::try_from(tokenizer),
70 Ok(Time {
71 active: Active {
72 start: 3724394400,
73 stop: 3724398000,
74 },
75 repeat: vec![
76 Repeat {
77 interval: TypedTime::None(Duration::seconds(604800)),
78 duration: TypedTime::None(Duration::seconds(3600)),
79 offsets: vec![TypedTime::None(Duration::seconds(0)),],
80 },
81 Repeat {
82 interval: TypedTime::Days(Duration::seconds(604800)),
83 duration: TypedTime::Hours(Duration::seconds(3600)),
84 offsets: vec![
85 TypedTime::None(Duration::seconds(0)),
86 TypedTime::Hours(Duration::seconds(90000)),
87 ],
88 }
89 ],
90 zone: Some(Zone {
91 parts: vec![
92 ZonePart {
93 adjustment_time: 3730928400,
94 offset: TypedTime::Hours(Duration::hours(-1)),
95 },
96 ZonePart {
97 adjustment_time: 3749680800,
98 offset: TypedTime::None(Duration::hours(0)),
99 },
100 ],
101 })
102 })
103 );
104 }
105
106 #[test]
107 fn from_tokenizer2() {
108 let tokenizer = Tokenizer {
109 active: ("3724394400", "3724398000").into(),
110 repeat: vec![],
111 zone: None,
112 };
113
114 assert_eq!(
115 Time::try_from(tokenizer),
116 Ok(Time {
117 active: Active {
118 start: 3724394400,
119 stop: 3724398000,
120 },
121 repeat: vec![],
122 zone: None
123 })
124 );
125 }
126
127 #[test]
128 fn display1() {
129 let time = Time {
130 active: Active {
131 start: 3724394400,
132 stop: 3724398000,
133 },
134 repeat: vec![
135 Repeat {
136 interval: TypedTime::None(Duration::seconds(604800)),
137 duration: TypedTime::None(Duration::seconds(3600)),
138 offsets: vec![TypedTime::None(Duration::seconds(0))],
139 },
140 Repeat {
141 interval: TypedTime::Days(Duration::seconds(604800)),
142 duration: TypedTime::Hours(Duration::seconds(3600)),
143 offsets: vec![
144 TypedTime::None(Duration::seconds(0)),
145 TypedTime::Hours(Duration::seconds(90000)),
146 ],
147 },
148 ],
149 zone: Some(Zone {
150 parts: vec![
151 ZonePart {
152 adjustment_time: 3730928400,
153 offset: TypedTime::Hours(Duration::hours(-1)),
154 },
155 ZonePart {
156 adjustment_time: 3749680800,
157 offset: TypedTime::None(Duration::hours(0)),
158 },
159 ],
160 }),
161 };
162
163 assert_eq!(
164 time.to_string(),
165 concat!(
166 "t=3724394400 3724398000\r\n",
167 "r=604800 3600 0\r\n",
168 "r=7d 1h 0 25h\r\n",
169 "z=3730928400 -1h 3749680800 0",
170 )
171 );
172 }
173
174 #[test]
175 fn display2() {
176 let time = Time {
177 active: Active {
178 start: 3724394400,
179 stop: 3724398000,
180 },
181 repeat: vec![],
182 zone: None,
183 };
184
185 assert_eq!(time.to_string(), concat!("t=3724394400 3724398000",));
186 }
187}