oddity_rtsp_protocol/
range.rs1use 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}