1#![allow(dead_code)]
3
4use derive_into_owned::IntoOwned;
5use enum_as_inner::EnumAsInner;
6use nom::{
7 branch::alt,
8 bytes::complete::{tag, take_while},
9 combinator::map,
10 sequence::{preceded, separated_pair, tuple},
11 IResult,
12};
13
14use std::borrow::Cow;
15
16use self::{
17 bandwidth::*, connection::*, email::*, media::*, origin::*, phone_number::*,
18 session_information::*, session_name::*, timing::*, uri::*, version::*,
19};
20
21#[derive(Clone, IntoOwned, EnumAsInner, PartialEq, Eq)]
23#[cfg_attr(feature = "debug", derive(Debug))]
24#[cfg_attr(
25 feature = "serde",
26 derive(serde::Serialize, serde::Deserialize),
27 serde(rename_all = "camelCase")
28)]
29#[non_exhaustive]
30pub enum SessionLine<'a> {
31 Version(Version),
33
34 Name(SessionName<'a>),
36
37 Timing(Timing),
39
40 Origin(Origin<'a>),
42
43 BandWidth(BandWidth),
45
46 Uri(Uri<'a>),
48
49 PhoneNumber(PhoneNumber<'a>),
51
52 EmailAddress(EmailAddress<'a>),
54
55 Connection(Connection),
57
58 Description(SessionInformation<'a>),
59
60 Media(Media<'a>),
62}
63
64pub fn session_line(input: &str) -> IResult<&str, SessionLine> {
65 alt((
66 map(version_line, SessionLine::Version),
68 map(name_line, SessionLine::Name),
69 map(description_line, SessionLine::Description),
70 map(bandwidth_line, SessionLine::BandWidth),
71 map(uri_line, SessionLine::Uri),
72 map(timing_line, SessionLine::Timing),
73 map(phone_number_line, SessionLine::PhoneNumber),
74 map(email_address_line, SessionLine::EmailAddress),
75 map(origin_line, SessionLine::Origin),
76 map(connection_line, SessionLine::Connection),
77 map(media_line, SessionLine::Media),
78 ))(input)
79}
80
81pub mod connection;
82pub mod media;
83pub mod origin;
84
85#[cfg(test)]
86use crate::assert_line;
87use crate::parsers::*;
88
89pub mod version {
90 use super::*;
91
92 #[derive(Clone, IntoOwned, PartialEq, Eq)]
93 #[cfg_attr(feature = "debug", derive(Debug))]
94 #[cfg_attr(
95 feature = "serde",
96 derive(serde::Serialize, serde::Deserialize),
97 serde(rename_all = "camelCase")
98 )]
99 pub struct Version(pub u32);
100
101 pub fn version_line(input: &str) -> IResult<&str, Version> {
103 preceded(tag("v="), map(wsf(read_number), Version))(input)
104 }
105
106 #[test]
107 fn test_version_line() {
108 assert_line!(version_line, "v=0", Version(0), print);
109 assert_line!(version_line, "v= 0");
110 }
111}
112
113pub mod session_name {
114 use super::*;
115
116 #[derive(Clone, IntoOwned, PartialEq, Eq)]
120 #[cfg_attr(feature = "debug", derive(Debug))]
121 #[cfg_attr(
122 feature = "serde",
123 derive(serde::Serialize, serde::Deserialize),
124 serde(rename_all = "camelCase")
125 )]
126 pub struct SessionName<'a>(pub Cow<'a, str>);
127
128 pub fn name_line(input: &str) -> IResult<&str, SessionName> {
130 line("s=", map(cowify(wsf(read_everything)), SessionName))(input)
131 }
132
133 #[test]
134 fn test_name_line() {
135 assert_line!(name_line, "s=", SessionName("".into()), print);
136 assert_line!(
137 name_line,
138 "s=testname",
139 SessionName("testname".into()),
140 print
141 );
142 assert_line!(name_line, "s= testname", SessionName("testname".into()));
143 assert_line!(name_line, "s=testname ", SessionName("testname".into()));
144 assert_line!(name_line, "s=test name ", SessionName("test name".into()));
145 }
146}
147
148pub mod session_information {
149 use super::*;
150
151 #[derive(Clone, IntoOwned, PartialEq, Eq)]
153 #[cfg_attr(feature = "debug", derive(Debug))]
154 #[cfg_attr(
155 feature = "serde",
156 derive(serde::Serialize, serde::Deserialize),
157 serde(rename_all = "camelCase")
158 )]
159 pub struct SessionInformation<'a>(pub Cow<'a, str>);
160
161 pub fn description_line(input: &str) -> IResult<&str, SessionInformation> {
163 line("i=", map(cowify(wsf(read_everything)), SessionInformation))(input)
164 }
165
166 #[test]
167 fn test_description_line() {
168 assert_line!(
169 description_line,
170 "i=test description",
171 SessionInformation("test description".into()),
172 print
173 );
174 assert_line!(
175 description_line,
176 "i=test description ",
177 SessionInformation("test description".into())
178 );
179 }
180}
181
182pub mod uri {
183 use super::*;
184 #[derive(Clone, IntoOwned, PartialEq, Eq)]
186 #[cfg_attr(feature = "debug", derive(Debug))]
187 #[cfg_attr(
188 feature = "serde",
189 derive(serde::Serialize, serde::Deserialize),
190 serde(rename_all = "camelCase")
191 )]
192 pub struct Uri<'a>(pub Cow<'a, str>);
193
194 pub fn uri_line(input: &str) -> IResult<&str, Uri> {
196 line("u=", map(cowify(read_string), Uri))(input)
197 }
198
199 #[test]
200 fn test_uri_line() {
201 assert_line!(
202 uri_line,
203 "u=https://parse-my.sdp",
204 Uri("https://parse-my.sdp".into())
205 );
206 }
207}
208
209pub mod email {
210
211 use super::*;
212
213 #[derive(Clone, IntoOwned, PartialEq, Eq)]
215 #[cfg_attr(feature = "debug", derive(Debug))]
216 #[cfg_attr(
217 feature = "serde",
218 derive(serde::Serialize, serde::Deserialize),
219 serde(rename_all = "camelCase")
220 )]
221 pub struct EmailAddress<'a>(pub Cow<'a, str>);
222
223 pub fn email_address_line(input: &str) -> IResult<&str, EmailAddress> {
225 line("e=", wsf(map(cowify(read_string), EmailAddress)))(input)
226 }
227
228 #[test]
229 fn test_email_address_line() {
230 assert_line!(
231 email_address_line,
232 "e=test@example.com",
233 EmailAddress("test@example.com".into()),
234 print
235 );
236 }
237}
238
239pub mod phone_number {
242 use super::*;
243 #[derive(Clone, IntoOwned, PartialEq, Eq)]
245 #[cfg_attr(feature = "debug", derive(Debug))]
246 #[cfg_attr(
247 feature = "serde",
248 derive(serde::Serialize, serde::Deserialize),
249 serde(rename_all = "camelCase")
250 )]
251 pub struct PhoneNumber<'a>(pub Cow<'a, str>);
252
253 pub fn phone_number_line(input: &str) -> IResult<&str, PhoneNumber> {
255 line("p=", map(cowify(take_while(|_| true)), PhoneNumber))(input)
256 }
257
258 #[test]
259 fn test_phone_number_line() {
260 assert_line!(
261 phone_number_line,
262 "p=0118 999 881 999 119 7253",
263 PhoneNumber("0118 999 881 999 119 7253".into()),
264 print
265 );
266 }
267}
268
269pub mod timing {
270 use super::*;
271
272 #[derive(Clone, PartialEq, Eq)]
274 #[cfg_attr(feature = "debug", derive(Debug))]
275 #[cfg_attr(
276 feature = "serde",
277 derive(serde::Serialize, serde::Deserialize),
278 serde(rename_all = "camelCase")
279 )]
280 pub struct Timing {
281 pub start: u32,
282 pub stop: u32,
283 }
284
285 pub fn timing_line(input: &str) -> IResult<&str, Timing> {
287 line(
288 "t=",
289 wsf(map(
290 tuple((wsf(read_number), wsf(read_number))),
291 |(start, stop)| Timing { start, stop },
292 )),
293 )(input)
294 }
295
296 #[test]
297 #[rustfmt::skip]
298 fn test_timing_line() {
299 assert_line!(timing_line,"t=0 1", Timing { start: 0, stop: 1 }, print);
300 assert_line!(timing_line,"t= 2 3 ", Timing { start: 2, stop: 3 });
301 assert_line!(timing_line,"t= 2 3 ", Timing { start: 2, stop: 3 });
302 assert_line!(timing_line,"t=23 42", Timing { start: 23, stop: 42 }, print);
303 }
304}
305
306pub mod bandwidth {
307 use super::*;
308 #[derive(Clone, PartialEq, Eq)]
309 #[cfg_attr(feature = "debug", derive(Debug))]
310 #[cfg_attr(
311 feature = "serde",
312 derive(serde::Serialize, serde::Deserialize),
313 serde(rename_all = "camelCase")
314 )]
315 #[non_exhaustive]
316 pub enum BandWidthType {
317 TIAS,
318 AS,
319 CT,
320 RR,
321 RS,
322 }
323 pub fn bandwidth_type(input: &str) -> IResult<&str, BandWidthType> {
325 alt((
326 map(tag("TIAS"), |_| BandWidthType::TIAS),
327 map(tag("AS"), |_| BandWidthType::AS),
328 map(tag("CT"), |_| BandWidthType::CT),
329 map(tag("RR"), |_| BandWidthType::RR),
330 map(tag("RS"), |_| BandWidthType::RS),
331 ))(input)
332 }
333
334 #[derive(Clone, PartialEq, Eq)]
335 #[cfg_attr(feature = "debug", derive(Debug))]
336 #[cfg_attr(
337 feature = "serde",
338 derive(serde::Serialize, serde::Deserialize),
339 serde(rename_all = "camelCase")
340 )]
341 pub struct BandWidth {
343 pub r#type: BandWidthType,
344 pub limit: u32,
345 }
346
347 pub fn bandwidth_line(input: &str) -> IResult<&str, BandWidth> {
349 line("b=", bandwidth)(input)
350 }
351
352 pub fn bandwidth(input: &str) -> IResult<&str, BandWidth> {
354 map(
355 separated_pair(bandwidth_type, tag(":"), read_number),
356 |(r#type, limit)| (BandWidth { r#type, limit }),
357 )(input)
358 }
359
360 #[test]
361 #[rustfmt::skip]
362 fn test_bandwidth_line() {
363 assert_line!(
364 bandwidth_line,"b=AS:30",
365 BandWidth { r#type: BandWidthType::AS, limit: 30 }, print
366 );
367 assert_line!(
368 bandwidth_line,"b=RR:1024",
369 BandWidth { r#type: BandWidthType::RR, limit: 1024 }, print
370 );
371 }
372}
373
374pub mod comment {
375 use super::*;
376
377 pub fn comment_line(input: &str) -> IResult<&str, &str> {
378 preceded(tag(";"), wsf(read_everything))(input)
379 }
380
381 #[test]
382 fn test_read_comment() {
383 assert_line!(
384 comment_line,
385 "; this should not be part of the document",
386 "this should not be part of the document"
387 )
388 }
389}