msf_rtsp/header/
session.rs1use std::{
4 borrow::{Borrow, Cow},
5 fmt::{self, Display, Formatter},
6 str::FromStr,
7};
8
9use crate::{Error, header::HeaderFieldValue};
10
11#[derive(Clone)]
13pub struct SessionHeader {
14 inner: SessionHeaderRef<'static>,
15}
16
17impl SessionHeader {
18 pub fn new<T>(id: T) -> Self
20 where
21 T: Into<String>,
22 {
23 let inner = SessionHeaderRef {
24 id: Cow::Owned(id.into()),
25 timeout: None,
26 };
27
28 Self { inner }
29 }
30
31 #[inline]
33 pub fn id(&self) -> &str {
34 self.inner.id()
35 }
36
37 #[inline]
39 pub fn timeout(&self) -> u64 {
40 self.inner.timeout()
41 }
42
43 #[inline]
45 pub const fn with_timeout(mut self, timeout: u64) -> Self {
46 self.inner.timeout = Some(timeout);
47 self
48 }
49}
50
51impl Borrow<SessionHeaderRef<'static>> for SessionHeader {
52 #[inline]
53 fn borrow(&self) -> &SessionHeaderRef<'static> {
54 &self.inner
55 }
56}
57
58impl Display for SessionHeader {
59 #[inline]
60 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
61 Display::fmt(Borrow::<SessionHeaderRef>::borrow(self), f)
62 }
63}
64
65impl From<SessionHeader> for HeaderFieldValue {
66 #[inline]
67 fn from(value: SessionHeader) -> Self {
68 HeaderFieldValue::from(value.to_string())
69 }
70}
71
72impl FromStr for SessionHeader {
73 type Err = Error;
74
75 #[inline]
76 fn from_str(header: &str) -> Result<Self, Self::Err> {
77 SessionHeaderRef::try_from(header).map(SessionHeaderRef::into_owned)
78 }
79}
80
81impl TryFrom<&HeaderFieldValue> for SessionHeader {
82 type Error = Error;
83
84 #[inline]
85 fn try_from(value: &HeaderFieldValue) -> Result<Self, Self::Error> {
86 SessionHeaderRef::try_from(value).map(SessionHeaderRef::into_owned)
87 }
88}
89
90#[derive(Clone)]
92pub struct SessionHeaderRef<'a> {
93 id: Cow<'a, str>,
94 timeout: Option<u64>,
95}
96
97impl<'a> SessionHeaderRef<'a> {
98 #[inline]
100 pub const fn new(id: &'a str) -> Self {
101 Self {
102 id: Cow::Borrowed(id),
103 timeout: None,
104 }
105 }
106}
107
108impl SessionHeaderRef<'_> {
109 #[inline]
111 pub fn id(&self) -> &str {
112 &self.id
113 }
114
115 #[inline]
117 pub fn timeout(&self) -> u64 {
118 self.timeout.unwrap_or(60)
119 }
120
121 #[inline]
123 pub const fn with_timeout(mut self, timeout: u64) -> Self {
124 self.timeout = Some(timeout);
125 self
126 }
127
128 #[inline]
130 pub fn into_owned(self) -> SessionHeader {
131 let inner = SessionHeaderRef {
132 id: Cow::Owned(self.id.into_owned()),
133 timeout: self.timeout,
134 };
135
136 SessionHeader { inner }
137 }
138
139 fn parse_params(&mut self, params: &str) -> Result<(), Error> {
141 for element in params.split(';') {
142 let (name, value) = super::parse_header_parameter(element);
143
144 if name.is_empty() {
145 continue;
146 }
147
148 self.parse_param(name, value)?;
149 }
150
151 Ok(())
152 }
153
154 fn parse_param(&mut self, name: &str, value: &str) -> Result<(), Error> {
156 if name.eq_ignore_ascii_case("timeout") {
157 self.timeout = value
158 .parse()
159 .map(Some)
160 .map_err(|_| Error::from_static_msg("invalid timeout parameter"))?;
161 }
162
163 Ok(())
164 }
165}
166
167impl Display for SessionHeaderRef<'_> {
168 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
169 write!(f, "{}", self.id)?;
170
171 if let Some(timeout) = self.timeout {
172 write!(f, ";timeout={timeout}")?;
173 }
174
175 Ok(())
176 }
177}
178
179impl From<SessionHeaderRef<'_>> for HeaderFieldValue {
180 #[inline]
181 fn from(value: SessionHeaderRef<'_>) -> Self {
182 HeaderFieldValue::from(value.to_string())
183 }
184}
185
186impl<'a> TryFrom<&'a str> for SessionHeaderRef<'a> {
187 type Error = Error;
188
189 fn try_from(header: &'a str) -> Result<Self, Self::Error> {
190 let (id, params) = header.split_once(';').unwrap_or((header, ""));
191
192 let mut res = Self::new(id);
193
194 res.parse_params(params)?;
195
196 Ok(res)
197 }
198}
199
200impl<'a> TryFrom<&'a HeaderFieldValue> for SessionHeaderRef<'a> {
201 type Error = Error;
202
203 fn try_from(value: &'a HeaderFieldValue) -> Result<Self, Self::Error> {
204 value
205 .to_str()
206 .map_err(|_| Error::from_static_msg("header field is not UTF-8 encoded"))?
207 .try_into()
208 }
209}