rtsp_types/headers/
accept_ranges.rs

1// Copyright (C) 2020 Sebastian Dröge <sebastian@centricular.com>
2//
3// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
4
5use super::*;
6
7use std::fmt;
8
9/// `Accept-Ranges` header ([RFC 7826 section 18.5](https://tools.ietf.org/html/rfc7826#section-18.5)).
10#[derive(Debug, Clone)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct AcceptRanges(Vec<RangeUnit>);
13
14/// Range units.
15#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub enum RangeUnit {
18    /// Normal playback time.
19    Npt,
20    /// SMPTE 30 frames per second timecodes.
21    Smpte,
22    /// SMPTE 30 frames per second timecodes with drop frames (29.97 fps).
23    Smpte30Drop,
24    /// SMPTE 25 frames per second timecodes.
25    Smpte25,
26    /// Absolute time (UTC).
27    Clock,
28    /// Extension range unit.
29    Extension(String),
30}
31
32impl RangeUnit {
33    pub fn as_str(&self) -> &str {
34        match self {
35            RangeUnit::Npt => "npt",
36            RangeUnit::Smpte => "smpte",
37            RangeUnit::Smpte30Drop => "smpte-30-drop",
38            RangeUnit::Smpte25 => "smpte-25",
39            RangeUnit::Clock => "clock",
40            RangeUnit::Extension(ref s) => s.as_str(),
41        }
42    }
43}
44
45impl fmt::Display for RangeUnit {
46    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47        f.write_str(self.as_str())
48    }
49}
50
51impl std::str::FromStr for RangeUnit {
52    type Err = HeaderParseError;
53
54    fn from_str(s: &str) -> Result<Self, HeaderParseError> {
55        match s {
56            "npt" => Ok(RangeUnit::Npt),
57            "smpte" => Ok(RangeUnit::Smpte),
58            "smpte-30-drop" => Ok(RangeUnit::Smpte30Drop),
59            "smpte-25" => Ok(RangeUnit::Smpte25),
60            "clock" => Ok(RangeUnit::Clock),
61            _ => Ok(RangeUnit::Extension(String::from(s))),
62        }
63    }
64}
65
66impl std::ops::Deref for AcceptRanges {
67    type Target = Vec<RangeUnit>;
68
69    fn deref(&self) -> &Self::Target {
70        &self.0
71    }
72}
73
74impl std::ops::DerefMut for AcceptRanges {
75    fn deref_mut(&mut self) -> &mut Self::Target {
76        &mut self.0
77    }
78}
79
80impl AsRef<Vec<RangeUnit>> for AcceptRanges {
81    fn as_ref(&self) -> &Vec<RangeUnit> {
82        &self.0
83    }
84}
85
86impl AsMut<Vec<RangeUnit>> for AcceptRanges {
87    fn as_mut(&mut self) -> &mut Vec<RangeUnit> {
88        &mut self.0
89    }
90}
91
92impl From<Vec<RangeUnit>> for AcceptRanges {
93    fn from(v: Vec<RangeUnit>) -> Self {
94        AcceptRanges(v)
95    }
96}
97
98impl<'a> From<&'a [RangeUnit]> for AcceptRanges {
99    fn from(v: &'a [RangeUnit]) -> Self {
100        AcceptRanges(v.to_vec())
101    }
102}
103
104impl AcceptRanges {
105    /// Creates a new `Accept-Ranges` header builder.
106    pub fn builder() -> AcceptRangesBuilder {
107        AcceptRangesBuilder(Vec::new())
108    }
109}
110
111/// Builder for the 'Accept-Ranges' header.
112#[derive(Debug, Clone)]
113pub struct AcceptRangesBuilder(Vec<RangeUnit>);
114
115impl AcceptRangesBuilder {
116    /// Add the provided range to the `Accept-Ranges` header.
117    pub fn range(mut self, range: RangeUnit) -> Self {
118        self.0.push(range);
119        self
120    }
121
122    /// Build the `Accept-Ranges` header.
123    pub fn build(self) -> AcceptRanges {
124        AcceptRanges(self.0)
125    }
126}
127
128impl super::TypedHeader for AcceptRanges {
129    fn from_headers(headers: impl AsRef<Headers>) -> Result<Option<Self>, HeaderParseError> {
130        let headers = headers.as_ref();
131
132        let header = match headers.get(&ACCEPT_RANGES) {
133            None => return Ok(None),
134            Some(header) => header,
135        };
136
137        let mut ranges = Vec::new();
138        for range in header.as_str().split(',') {
139            let range = range.trim();
140
141            ranges.push(range.parse()?);
142        }
143
144        Ok(Some(AcceptRanges(ranges)))
145    }
146
147    fn insert_into(&self, mut headers: impl AsMut<Headers>) {
148        let headers = headers.as_mut();
149
150        let mut ranges = String::new();
151        for range in &self.0 {
152            if !ranges.is_empty() {
153                ranges.push_str(", ");
154            }
155
156            ranges.push_str(range.as_str());
157        }
158
159        headers.insert(ACCEPT_RANGES, ranges);
160    }
161}
162
163impl super::TypedAppendableHeader for AcceptRanges {
164    fn append_to(&self, mut headers: impl AsMut<Headers>) {
165        let headers = headers.as_mut();
166
167        let mut ranges = String::new();
168        for range in &self.0 {
169            if !ranges.is_empty() {
170                ranges.push_str(", ");
171            }
172
173            ranges.push_str(range.as_str());
174        }
175
176        headers.append(ACCEPT_RANGES, ranges);
177    }
178}