sdp_rs/tokenizers/
media.rs

1use crate::TResult;
2
3#[derive(Debug, PartialEq, Eq, Clone)]
4pub struct Tokenizer<'a> {
5    pub media: &'a str,
6    pub port: PortTokenizer<'a>,
7    pub proto: &'a str,
8    pub fmt: &'a str,
9}
10
11impl<'a> Tokenizer<'a> {
12    pub fn tokenize(part: &'a str) -> TResult<'a, Self> {
13        use crate::parser_utils::*;
14        use nom::{bytes::complete::tag, sequence::preceded};
15
16        let (rem, line) = preceded(tag("m="), until_newline)(part)?;
17        let (line_rem, media) = until_space(line)?;
18        let (line_rem, port_with_num_of_ports) = until_space(line_rem)?;
19        let (fmt, proto) = until_space(line_rem)?;
20        let (_, port) = PortTokenizer::tokenize(port_with_num_of_ports)?;
21
22        Ok((
23            rem,
24            Tokenizer {
25                media,
26                port,
27                proto,
28                fmt,
29            },
30        ))
31    }
32}
33
34#[derive(Debug, PartialEq, Eq, Clone)]
35pub struct PortTokenizer<'a> {
36    pub port: &'a str,
37    pub num_of_ports: Option<&'a str>,
38}
39
40impl<'a> PortTokenizer<'a> {
41    pub fn tokenize(part: &'a str) -> TResult<'a, Self> {
42        use nom::{
43            branch::alt,
44            bytes::complete::{tag, take_until},
45            combinator::rest,
46            sequence::terminated,
47        };
48
49        let (num_of_ports, port) = alt((terminated(take_until("/"), tag("/")), rest))(part)?;
50        let num_of_ports = match num_of_ports.is_empty() {
51            true => None,
52            false => Some(num_of_ports),
53        };
54
55        Ok(("", (port, num_of_ports).into()))
56    }
57}
58
59impl<'a> From<(&'a str, Option<&'a str>)> for PortTokenizer<'a> {
60    fn from((port, num_of_ports): (&'a str, Option<&'a str>)) -> Self {
61        Self { port, num_of_ports }
62    }
63}
64
65impl<'a> From<(&'a str, &'a str)> for PortTokenizer<'a> {
66    fn from((port, num_of_ports): (&'a str, &'a str)) -> Self {
67        Self {
68            port,
69            num_of_ports: Some(num_of_ports),
70        }
71    }
72}
73
74impl<'a> From<&'a str> for PortTokenizer<'a> {
75    fn from(port: &'a str) -> Self {
76        Self {
77            port,
78            num_of_ports: None,
79        }
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn tokenizer1() {
89        let media = concat!("m=audio 49170 RTP/AVP 0\r\nsomething");
90
91        assert_eq!(
92            Tokenizer::tokenize(media),
93            Ok((
94                "something",
95                Tokenizer {
96                    media: "audio",
97                    port: ("49170", None).into(),
98                    proto: "RTP/AVP",
99                    fmt: "0",
100                }
101            )),
102        );
103    }
104
105    #[test]
106    fn tokenizer2() {
107        let media = concat!("m=video 49170/2 RTP/AVP 31\r\nsomething");
108
109        assert_eq!(
110            Tokenizer::tokenize(media),
111            Ok((
112                "something",
113                Tokenizer {
114                    media: "video",
115                    port: ("49170", "2").into(),
116                    proto: "RTP/AVP",
117                    fmt: "31",
118                }
119            )),
120        );
121    }
122}