1use std::{
4 fmt::{self, Display, Formatter},
5 ops::{Deref, DerefMut},
6 str::FromStr,
7};
8
9use str_reader::StringReader;
10
11use crate::{
12 parser::{FromSessionDescriptionLines, SessionDescriptionLines},
13 ParseError,
14};
15
16#[derive(Clone)]
18pub struct TimeDescription {
19 start: u64,
20 stop: u64,
21 repeat_times: Vec<RepeatTime>,
22}
23
24impl TimeDescription {
25 #[inline]
27 pub fn new<T>(start: u64, stop: u64, repeat_times: T) -> Self
28 where
29 T: Into<Vec<RepeatTime>>,
30 {
31 Self {
32 start,
33 stop,
34 repeat_times: repeat_times.into(),
35 }
36 }
37
38 #[inline]
40 pub fn start(&self) -> u64 {
41 self.start
42 }
43
44 #[inline]
46 pub fn stop(&self) -> u64 {
47 self.stop
48 }
49
50 #[inline]
52 pub fn repeat_times(&self) -> &[RepeatTime] {
53 &self.repeat_times
54 }
55}
56
57impl Default for TimeDescription {
58 #[inline]
59 fn default() -> Self {
60 Self::new(0, 0, Vec::new())
61 }
62}
63
64impl Display for TimeDescription {
65 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
66 write!(f, "t={} {}\r\n", self.start, self.stop)?;
67
68 for repeat in &self.repeat_times {
69 write!(f, "r={repeat}\r\n")?;
70 }
71
72 Ok(())
73 }
74}
75
76impl FromSessionDescriptionLines for TimeDescription {
77 fn from_sdp_lines(lines: &mut SessionDescriptionLines) -> Result<Self, ParseError> {
78 let (t, v) = lines.current().unwrap();
79
80 debug_assert_eq!(t, 't');
81
82 let mut reader = StringReader::new(v);
83
84 let mut res = Self {
85 start: reader.read_u64()?,
86 stop: reader.read_u64()?,
87 repeat_times: Vec::new(),
88 };
89
90 reader.skip_whitespace();
91
92 if !reader.is_empty() {
93 return Err(ParseError::plain());
94 }
95
96 lines.next()?;
97
98 while let Some((t, _)) = lines.current() {
99 if t == 'r' {
100 let repeat_time = lines
101 .parse()
102 .map_err(|err| ParseError::with_cause_and_msg("invalid repeat time", err))?;
103
104 res.repeat_times.push(repeat_time);
105 } else {
106 break;
107 }
108 }
109
110 Ok(res)
111 }
112}
113
114#[derive(Clone)]
116pub struct RepeatTime {
117 repeat_interval: UnsignedCompactDuration,
118 active_duration: UnsignedCompactDuration,
119 offsets: Vec<UnsignedCompactDuration>,
120}
121
122impl RepeatTime {
123 #[inline]
125 pub fn new<T>(
126 repeat_interval: UnsignedCompactDuration,
127 active_duration: UnsignedCompactDuration,
128 offsets: T,
129 ) -> Self
130 where
131 T: Into<Vec<UnsignedCompactDuration>>,
132 {
133 Self {
134 repeat_interval,
135 active_duration,
136 offsets: offsets.into(),
137 }
138 }
139
140 #[inline]
142 pub fn repeat_interval(&self) -> UnsignedCompactDuration {
143 self.repeat_interval
144 }
145
146 #[inline]
148 pub fn active_duration(&self) -> UnsignedCompactDuration {
149 self.active_duration
150 }
151
152 #[inline]
154 pub fn offsets(&self) -> &[UnsignedCompactDuration] {
155 &self.offsets
156 }
157}
158
159impl Display for RepeatTime {
160 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
161 write!(f, "{} {}", self.repeat_interval, self.active_duration)?;
162
163 for offset in &self.offsets {
164 write!(f, " {offset}")?;
165 }
166
167 Ok(())
168 }
169}
170
171impl FromStr for RepeatTime {
172 type Err = ParseError;
173
174 fn from_str(s: &str) -> Result<Self, Self::Err> {
175 let mut reader = StringReader::new(s);
176
177 let mut res = Self {
178 repeat_interval: reader.parse_word()?,
179 active_duration: reader.parse_word()?,
180 offsets: Vec::new(),
181 };
182
183 loop {
184 reader.skip_whitespace();
185
186 if reader.is_empty() {
187 return Ok(res);
188 }
189
190 res.offsets.push(reader.parse_word()?);
191 }
192 }
193}
194
195#[derive(Copy, Clone)]
197pub struct TimeZoneAdjustment {
198 adjustment_time: u64,
199 offset: CompactDuration,
200}
201
202impl TimeZoneAdjustment {
203 #[inline]
205 pub const fn new(adjustment_time: u64, offset: CompactDuration) -> Self {
206 Self {
207 adjustment_time,
208 offset,
209 }
210 }
211
212 #[inline]
214 pub fn adjustment_time(&self) -> u64 {
215 self.adjustment_time
216 }
217
218 #[inline]
220 pub fn offset(&self) -> CompactDuration {
221 self.offset
222 }
223}
224
225impl Display for TimeZoneAdjustment {
226 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
227 write!(f, "{} {}", self.adjustment_time, self.offset)
228 }
229}
230
231impl FromStr for TimeZoneAdjustment {
232 type Err = ParseError;
233
234 fn from_str(s: &str) -> Result<Self, Self::Err> {
235 let mut reader = StringReader::new(s);
236
237 let res = Self {
238 adjustment_time: reader.read_u64()?,
239 offset: reader.parse_word()?,
240 };
241
242 reader.skip_whitespace();
243
244 if reader.is_empty() {
245 Ok(res)
246 } else {
247 Err(ParseError::plain())
248 }
249 }
250}
251
252#[derive(Clone)]
254pub struct TimeZoneAdjustments {
255 inner: Vec<TimeZoneAdjustment>,
256}
257
258impl TimeZoneAdjustments {
259 #[inline]
261 pub const fn empty() -> Self {
262 Self { inner: Vec::new() }
263 }
264}
265
266impl Deref for TimeZoneAdjustments {
267 type Target = Vec<TimeZoneAdjustment>;
268
269 #[inline]
270 fn deref(&self) -> &Self::Target {
271 &self.inner
272 }
273}
274
275impl DerefMut for TimeZoneAdjustments {
276 #[inline]
277 fn deref_mut(&mut self) -> &mut Self::Target {
278 &mut self.inner
279 }
280}
281
282impl Display for TimeZoneAdjustments {
283 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
284 let mut iter = self.inner.iter();
285
286 if let Some(adj) = iter.next() {
287 write!(f, "{adj}")?;
288 }
289
290 for adj in iter {
291 write!(f, " {adj}")?;
292 }
293
294 Ok(())
295 }
296}
297
298impl FromStr for TimeZoneAdjustments {
299 type Err = ParseError;
300
301 fn from_str(s: &str) -> Result<Self, Self::Err> {
302 let mut reader = StringReader::new(s);
303
304 let mut res = Self::empty();
305
306 loop {
307 let adjustment_time = reader.read_u64()?;
308 let offset = reader.parse_word()?;
309
310 res.inner
311 .push(TimeZoneAdjustment::new(adjustment_time, offset));
312
313 reader.skip_whitespace();
314
315 if reader.is_empty() {
316 return Ok(res);
317 }
318 }
319 }
320}
321
322#[derive(Copy, Clone)]
324pub enum CompactDuration {
325 Seconds(i64),
326 Minutes(i64),
327 Hours(i64),
328 Days(i64),
329}
330
331impl CompactDuration {
332 #[inline]
334 pub fn as_secs(&self) -> i64 {
335 match *self {
336 Self::Seconds(n) => n,
337 Self::Minutes(n) => n * 60,
338 Self::Hours(n) => n * 3_600,
339 Self::Days(n) => n * 86_400,
340 }
341 }
342}
343
344impl Display for CompactDuration {
345 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
346 match self {
347 Self::Seconds(v) => write!(f, "{v}"),
348 Self::Minutes(v) => write!(f, "{v}m"),
349 Self::Hours(v) => write!(f, "{v}h"),
350 Self::Days(v) => write!(f, "{v}d"),
351 }
352 }
353}
354
355impl FromStr for CompactDuration {
356 type Err = ParseError;
357
358 fn from_str(s: &str) -> Result<Self, Self::Err> {
359 let mut reader = StringReader::new(s.trim());
360
361 let n = reader
362 .read_until(|c| !c.is_ascii_digit() && c != '-')
363 .parse()?;
364
365 let res = match reader.current_char() {
366 Some('s') => Self::Seconds(n),
367 Some('m') => Self::Minutes(n),
368 Some('h') => Self::Hours(n),
369 Some('d') => Self::Days(n),
370 None => Self::Seconds(n),
371 _ => return Err(ParseError::plain()),
372 };
373
374 if reader.is_empty() {
375 Ok(res)
376 } else {
377 Err(ParseError::plain())
378 }
379 }
380}
381
382#[derive(Copy, Clone)]
384pub enum UnsignedCompactDuration {
385 Seconds(u64),
386 Minutes(u64),
387 Hours(u64),
388 Days(u64),
389}
390
391impl UnsignedCompactDuration {
392 #[inline]
394 pub fn as_secs(&self) -> u64 {
395 match *self {
396 Self::Seconds(n) => n,
397 Self::Minutes(n) => n * 60,
398 Self::Hours(n) => n * 3_600,
399 Self::Days(n) => n * 86_400,
400 }
401 }
402}
403
404impl Display for UnsignedCompactDuration {
405 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
406 match self {
407 Self::Seconds(v) => write!(f, "{v}"),
408 Self::Minutes(v) => write!(f, "{v}m"),
409 Self::Hours(v) => write!(f, "{v}h"),
410 Self::Days(v) => write!(f, "{v}d"),
411 }
412 }
413}
414
415impl FromStr for UnsignedCompactDuration {
416 type Err = ParseError;
417
418 fn from_str(s: &str) -> Result<Self, Self::Err> {
419 let mut reader = StringReader::new(s.trim());
420
421 let n = reader.read_until(|c| !c.is_ascii_digit()).parse()?;
422
423 let res = match reader.current_char() {
424 Some('s') => Self::Seconds(n),
425 Some('m') => Self::Minutes(n),
426 Some('h') => Self::Hours(n),
427 Some('d') => Self::Days(n),
428 None => Self::Seconds(n),
429 _ => return Err(ParseError::plain()),
430 };
431
432 if reader.is_empty() {
433 Ok(res)
434 } else {
435 Err(ParseError::plain())
436 }
437 }
438}