sdp_rs/lines/connection/
connection_address.rs

1use crate::Error;
2use std::{convert::TryFrom, net::IpAddr};
3
4/// The connection address tokenizer, which is part of the connection (`c=`) line. This is low
5/// level stuff and you shouldn't interact directly with it, unless you know what you are doing.
6pub use crate::tokenizers::connection::connection_address::Tokenizer;
7
8/// The connection address of the connection line (`c=`).
9#[derive(Debug, PartialEq, Eq, Ord, PartialOrd, Clone, Copy)]
10pub struct ConnectionAddress {
11    pub base: IpAddr,
12    pub ttl: Option<u32>,
13    pub numaddr: Option<u32>,
14}
15
16impl<'a> TryFrom<Tokenizer<'a>> for ConnectionAddress {
17    type Error = Error;
18
19    fn try_from(tokenizer: Tokenizer<'a>) -> Result<Self, Self::Error> {
20        Ok(Self {
21            base: tokenizer.base.parse().map_err(|e| {
22                Self::Error::parser_with_error("connection address base", tokenizer.base, e)
23            })?,
24            ttl: tokenizer
25                .ttl
26                .map(|ttl| {
27                    ttl.parse().map_err(|e| {
28                        Self::Error::parser_with_error("connection address ttl", ttl, e)
29                    })
30                })
31                .transpose()?,
32            numaddr: tokenizer
33                .numaddr
34                .map(|numaddr| {
35                    numaddr.parse().map_err(|e| {
36                        Self::Error::parser_with_error("connection number of addresses", numaddr, e)
37                    })
38                })
39                .transpose()?,
40        })
41    }
42}
43
44impl<'a> From<IpAddr> for ConnectionAddress {
45    fn from(base: IpAddr) -> Self {
46        Self {
47            base,
48            ttl: None,
49            numaddr: None,
50        }
51    }
52}
53
54impl std::fmt::Display for ConnectionAddress {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        match (self.ttl, self.numaddr) {
57            (Some(ttl), Some(numaddr)) => write!(f, "{}/{}/{}", self.base, ttl, numaddr),
58            (Some(ttl), None) => write!(f, "{}/{}", self.base, ttl),
59            (None, Some(numaddr)) => write!(f, "{}/{}", self.base, numaddr),
60            (None, None) => write!(f, "{}", self.base),
61        }
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn from_tokenizer1() {
71        let tokenizer: Tokenizer = "233.252.0.1".into();
72
73        assert_eq!(
74            ConnectionAddress::try_from(tokenizer),
75            Ok(ConnectionAddress {
76                base: "233.252.0.1".parse().unwrap(),
77                ttl: None,
78                numaddr: None
79            })
80        );
81    }
82
83    #[test]
84    fn from_tokenizer2() {
85        let tokenizer: Tokenizer = ("233.252.0.1", Some("127"), None).into();
86
87        assert_eq!(
88            ConnectionAddress::try_from(tokenizer),
89            Ok(ConnectionAddress {
90                base: "233.252.0.1".parse().unwrap(),
91                ttl: Some(127),
92                numaddr: None
93            })
94        );
95    }
96
97    #[test]
98    fn from_tokenizer3() {
99        let tokenizer: Tokenizer = ("233.252.0.1", Some("127"), Some("2")).into();
100
101        assert_eq!(
102            ConnectionAddress::try_from(tokenizer),
103            Ok(ConnectionAddress {
104                base: "233.252.0.1".parse().unwrap(),
105                ttl: Some(127),
106                numaddr: Some(2)
107            })
108        );
109    }
110
111    #[test]
112    fn display1() {
113        let connection = ConnectionAddress {
114            base: "233.252.0.1".parse().unwrap(),
115            ttl: Some(127),
116            numaddr: Some(2),
117        };
118
119        assert_eq!(connection.to_string(), "233.252.0.1/127/2");
120    }
121}