oddity_rtsp_protocol/
range.rs

1use std::fmt;
2use std::str::FromStr;
3
4use super::Error;
5
6#[derive(Debug, Clone, PartialEq)]
7pub struct Range {
8    pub start: Option<NptTime>,
9    pub end: Option<NptTime>,
10}
11
12impl Range {
13    const SUPPORTED_UNITS: [&'static str; 1] = ["npt"];
14
15    pub fn new(start: NptTime, end: NptTime) -> Range {
16        Range {
17            start: Some(start),
18            end: Some(end),
19        }
20    }
21
22    pub fn new_for_live() -> Range {
23        Range {
24            start: Some(NptTime::Now),
25            end: None,
26        }
27    }
28}
29
30impl fmt::Display for Range {
31    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32        write!(f, "npt=")?;
33        match (self.start.as_ref(), self.end.as_ref()) {
34            (Some(start), Some(end)) => write!(f, "{}-{}", start, end),
35            (Some(start), None) => write!(f, "{}-", start),
36            (None, Some(end)) => write!(f, "-{}", end),
37            (None, None) => write!(f, "-"),
38        }
39    }
40}
41
42impl FromStr for Range {
43    type Err = Error;
44
45    fn from_str(s: &str) -> Result<Self, Self::Err> {
46        match s.split_once(';') {
47            None => {
48                if let Some((unit, value)) = s.split_once('=') {
49                    if Self::SUPPORTED_UNITS.contains(&unit) {
50                        if let Some((start, end)) = value.split_once('-') {
51                            let start = if !start.is_empty() {
52                                Some(start.parse()?)
53                            } else {
54                                None
55                            };
56                            let end = if !end.is_empty() {
57                                Some(end.parse()?)
58                            } else {
59                                None
60                            };
61                            Ok(Range { start, end })
62                        } else {
63                            Err(Error::RangeMalformed {
64                                value: s.to_string(),
65                            })
66                        }
67                    } else {
68                        Err(Error::RangeUnitNotSupported {
69                            value: s.to_string(),
70                        })
71                    }
72                } else {
73                    Err(Error::RangeMalformed {
74                        value: s.to_string(),
75                    })
76                }
77            }
78            Some((_, time)) => {
79                if time.starts_with("time=") {
80                    Err(Error::RangeTimeNotSupported {
81                        value: s.to_string(),
82                    })
83                } else {
84                    Err(Error::RangeMalformed {
85                        value: s.to_string(),
86                    })
87                }
88            }
89        }
90    }
91}
92
93#[derive(Debug, Clone, PartialEq)]
94pub enum NptTime {
95    Now,
96    Time(f64),
97}
98
99impl fmt::Display for NptTime {
100    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101        match self {
102            NptTime::Now => write!(f, "now"),
103            NptTime::Time(seconds) => write!(f, "{:.3}", seconds),
104        }
105    }
106}
107
108impl FromStr for NptTime {
109    type Err = Error;
110
111    fn from_str(s: &str) -> Result<Self, Self::Err> {
112        match s {
113            "now" => Ok(NptTime::Now),
114            s => match *s.split(':').collect::<Vec<_>>().as_slice() {
115                [npt_time] => {
116                    let npt_time =
117                        npt_time
118                            .parse::<f64>()
119                            .map_err(|_| Error::RangeNptTimeMalfored {
120                                value: s.to_string(),
121                            })?;
122                    Ok(NptTime::Time(npt_time))
123                }
124                [npt_hh, npt_mm, npt_ss] => {
125                    let npt_hh = npt_hh.parse::<u32>();
126                    let npt_mm = npt_mm.parse::<u32>();
127                    let npt_secs = npt_ss.parse::<f32>();
128                    match (npt_hh, npt_mm, npt_secs) {
129                        (Ok(hh), Ok(mm), Ok(secs)) => {
130                            let npt_time =
131                                ((hh * 3600) as f64) + ((mm * 60) as f64) + (secs as f64);
132                            Ok(NptTime::Time(npt_time))
133                        }
134                        _ => Err(Error::RangeNptTimeMalfored {
135                            value: s.to_string(),
136                        }),
137                    }
138                }
139                _ => Err(Error::RangeNptTimeMalfored {
140                    value: s.to_string(),
141                }),
142            },
143        }
144    }
145}