ezk_sdp_types/
connection.rs

1use crate::{slash_num, TaggedAddress};
2use bytes::Bytes;
3use internal::IResult;
4use nom::combinator::opt;
5use nom::sequence::pair;
6use std::fmt;
7
8/// Connection field (`c=`)
9///
10/// [RFC8866](https://www.rfc-editor.org/rfc/rfc8866.html#section-5.7)
11#[derive(Debug, Clone)]
12pub struct Connection {
13    /// The connection address
14    pub address: TaggedAddress,
15
16    /// Must be set for IPv4 multicast sessions
17    pub ttl: Option<u32>,
18
19    /// Number of addresses
20    pub num: Option<u32>,
21}
22
23impl Connection {
24    pub fn parse<'i>(src: &Bytes, i: &'i str) -> IResult<&'i str, Self> {
25        let (i, address) = TaggedAddress::parse(src)(i)?;
26
27        match &address {
28            TaggedAddress::IP4(_) | TaggedAddress::IP4FQDN(_) => {
29                let (i, ttl) = opt(pair(slash_num, opt(slash_num)))(i)?;
30
31                let (ttl, num) = match ttl {
32                    None => (None, None),
33                    Some((ttl, num)) => (Some(ttl), num),
34                };
35
36                Ok((i, Connection { address, ttl, num }))
37            }
38            TaggedAddress::IP6(_) | TaggedAddress::IP6FQDN(_) => {
39                let (i, num) = opt(slash_num)(i)?;
40
41                Ok((
42                    i,
43                    Connection {
44                        address,
45                        ttl: None,
46                        num,
47                    },
48                ))
49            }
50        }
51    }
52}
53
54impl fmt::Display for Connection {
55    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56        write!(f, "{}", self.address)?;
57
58        match self.address {
59            TaggedAddress::IP4(_) | TaggedAddress::IP4FQDN(_) => {
60                if let Some(ttl) = self.ttl {
61                    write!(f, "/{}", ttl)?;
62
63                    if let Some(num) = self.num {
64                        write!(f, "/{}", num)?;
65                    }
66                }
67            }
68            TaggedAddress::IP6(_) | TaggedAddress::IP6FQDN(_) => {
69                if let Some(num) = self.num {
70                    write!(f, "/{}", num)?;
71                }
72            }
73        }
74
75        Ok(())
76    }
77}
78
79#[cfg(test)]
80mod test {
81    use super::*;
82    use bytesstr::BytesStr;
83    use std::net::Ipv4Addr;
84
85    #[test]
86    fn connection() {
87        let input = BytesStr::from_static("IN IP4 192.168.123.222");
88
89        let (rem, connection) = Connection::parse(input.as_ref(), &input).unwrap();
90
91        assert!(rem.is_empty());
92
93        assert!(
94            matches!(connection.address, TaggedAddress::IP4(ip) if ip == Ipv4Addr::new(192, 168, 123, 222))
95        )
96    }
97
98    #[test]
99    fn connection_ttl() {
100        let input = BytesStr::from_static("IN IP4 192.168.123.222/127");
101
102        let (rem, connection) = Connection::parse(input.as_ref(), &input).unwrap();
103
104        assert!(rem.is_empty());
105
106        assert!(
107            matches!(connection.address, TaggedAddress::IP4(ip) if ip == Ipv4Addr::new(192, 168, 123, 222))
108        );
109        assert_eq!(connection.ttl, Some(127));
110        assert_eq!(connection.num, None);
111    }
112
113    #[test]
114    fn connection_ttl_num() {
115        let input = BytesStr::from_static("IN IP4 192.168.123.222/127/3");
116
117        let (rem, connection) = Connection::parse(input.as_ref(), &input).unwrap();
118
119        assert!(rem.is_empty());
120
121        assert!(
122            matches!(connection.address, TaggedAddress::IP4(ip) if ip == Ipv4Addr::new(192, 168, 123, 222))
123        );
124        assert_eq!(connection.ttl, Some(127));
125        assert_eq!(connection.num, Some(3));
126    }
127
128    #[test]
129    fn connection_print() {
130        let connection = Connection {
131            address: TaggedAddress::IP4(Ipv4Addr::new(192, 168, 123, 222)),
132            ttl: None,
133            num: None,
134        };
135
136        assert_eq!(connection.to_string(), "IN IP4 192.168.123.222");
137    }
138
139    #[test]
140    fn connection_print_ttl() {
141        let connection = Connection {
142            address: TaggedAddress::IP4(Ipv4Addr::new(192, 168, 0, 1)),
143            ttl: Some(127),
144            num: None,
145        };
146
147        assert_eq!(connection.to_string(), "IN IP4 192.168.0.1/127");
148    }
149
150    #[test]
151    fn connection_print_ttl_num() {
152        let connection = Connection {
153            address: TaggedAddress::IP4(Ipv4Addr::new(192, 168, 0, 1)),
154            ttl: Some(127),
155            num: Some(3),
156        };
157
158        assert_eq!(connection.to_string(), "IN IP4 192.168.0.1/127/3");
159    }
160
161    #[test]
162    fn connection_print_num_without_ttl() {
163        let connection = Connection {
164            address: TaggedAddress::IP4(Ipv4Addr::new(192, 168, 0, 1)),
165            ttl: None,
166            num: Some(3),
167        };
168
169        assert_eq!(connection.to_string(), "IN IP4 192.168.0.1");
170    }
171}