1extern crate url;
6use self::url::Host;
7use error::SdpParserInternalError;
8use std::convert::TryFrom;
9use std::fmt;
10use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
11use std::str::FromStr;
12
13#[derive(Clone, Debug)]
14#[cfg_attr(feature = "serialize", derive(Serialize))]
15pub enum Address {
16 Fqdn(String),
17 Ip(IpAddr),
18}
19
20impl fmt::Display for Address {
21 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22 match self {
23 Address::Fqdn(fqdn) => fqdn.fmt(f),
24 Address::Ip(ip) => ip.fmt(f),
25 }
26 }
27}
28
29impl FromStr for Address {
30 type Err = SdpParserInternalError;
31 fn from_str(s: &str) -> Result<Self, Self::Err> {
32 let mut e: Option<SdpParserInternalError> = None;
33 if s.find(':').is_some() {
34 match IpAddr::from_str(s) {
35 Ok(ip) => return Ok(Address::Ip(ip)),
36 Err(err) => e = Some(err.into()),
37 }
38 }
39 Host::parse(s)
40 .map(|host| match host {
41 Host::Domain(s) => Address::Fqdn(s),
42 Host::Ipv4(ip) => Address::Ip(IpAddr::V4(ip)),
43 Host::Ipv6(ip) => Address::Ip(IpAddr::V6(ip)),
44 })
45 .map_err(|err| e.unwrap_or_else(|| err.into()))
46 }
47}
48
49impl From<ExplicitlyTypedAddress> for Address {
50 fn from(item: ExplicitlyTypedAddress) -> Self {
51 match item {
52 ExplicitlyTypedAddress::Fqdn { domain, .. } => Address::Fqdn(domain),
53 ExplicitlyTypedAddress::Ip(ip) => Address::Ip(ip),
54 }
55 }
56}
57
58impl PartialEq for Address {
59 fn eq(&self, other: &Self) -> bool {
60 match (self, other) {
61 (Address::Fqdn(a), Address::Fqdn(b)) => a.to_lowercase() == b.to_lowercase(),
62 (Address::Ip(a), Address::Ip(b)) => a == b,
63 (_, _) => false,
64 }
65 }
66}
67
68#[derive(Clone, Copy, PartialEq, Debug)]
69#[cfg_attr(feature = "serialize", derive(Serialize))]
70pub enum AddressType {
71 IpV4 = 4,
72 IpV6 = 6,
73}
74
75impl fmt::Display for AddressType {
76 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77 match self {
78 AddressType::IpV4 => "IP4",
79 AddressType::IpV6 => "IP6",
80 }
81 .fmt(f)
82 }
83}
84
85impl FromStr for AddressType {
86 type Err = SdpParserInternalError;
87 fn from_str(s: &str) -> Result<Self, Self::Err> {
88 match s.to_uppercase().as_str() {
89 "IP4" => Ok(AddressType::IpV4),
90 "IP6" => Ok(AddressType::IpV6),
91 _ => Err(SdpParserInternalError::UnknownAddressType(s.to_owned())),
92 }
93 }
94}
95
96pub trait AddressTyped {
97 fn address_type(&self) -> AddressType;
98}
99
100impl AddressTyped for IpAddr {
101 fn address_type(&self) -> AddressType {
102 match self {
103 IpAddr::V4(_) => AddressType::IpV4,
104 IpAddr::V6(_) => AddressType::IpV6,
105 }
106 }
107}
108
109#[derive(Clone, Debug)]
110#[cfg_attr(feature = "serialize", derive(Serialize))]
111pub enum ExplicitlyTypedAddress {
112 Fqdn {
113 address_type: AddressType,
114 domain: String,
115 },
116 Ip(IpAddr),
117}
118
119impl fmt::Display for ExplicitlyTypedAddress {
120 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121 write!(f, "IN {} ", self.address_type())?;
122 match self {
123 ExplicitlyTypedAddress::Fqdn { domain, .. } => domain.fmt(f),
124 ExplicitlyTypedAddress::Ip(ip) => ip.fmt(f),
125 }
126 }
127}
128
129impl AddressTyped for ExplicitlyTypedAddress {
130 fn address_type(&self) -> AddressType {
131 match self {
132 ExplicitlyTypedAddress::Fqdn { address_type, .. } => *address_type,
133 ExplicitlyTypedAddress::Ip(ip) => ip.address_type(),
134 }
135 }
136}
137
138impl From<IpAddr> for ExplicitlyTypedAddress {
139 fn from(item: IpAddr) -> Self {
140 ExplicitlyTypedAddress::Ip(item)
141 }
142}
143
144impl From<Ipv4Addr> for ExplicitlyTypedAddress {
145 fn from(item: Ipv4Addr) -> Self {
146 ExplicitlyTypedAddress::Ip(IpAddr::V4(item))
147 }
148}
149
150impl From<Ipv6Addr> for ExplicitlyTypedAddress {
151 fn from(item: Ipv6Addr) -> Self {
152 ExplicitlyTypedAddress::Ip(IpAddr::V6(item))
153 }
154}
155
156impl TryFrom<(AddressType, &str)> for ExplicitlyTypedAddress {
157 type Error = SdpParserInternalError;
158 fn try_from(item: (AddressType, &str)) -> Result<Self, Self::Error> {
159 match Address::from_str(item.1)? {
160 Address::Ip(ip) => {
161 if ip.address_type() != item.0 {
162 Err(SdpParserInternalError::AddressTypeMismatch {
163 found: ip.address_type(),
164 expected: item.0,
165 })
166 } else {
167 Ok(ExplicitlyTypedAddress::Ip(ip))
168 }
169 }
170 Address::Fqdn(domain) => Ok(ExplicitlyTypedAddress::Fqdn {
171 address_type: item.0,
172 domain,
173 }),
174 }
175 }
176}
177
178impl PartialEq for ExplicitlyTypedAddress {
179 fn eq(&self, other: &Self) -> bool {
180 match (self, other) {
181 (
182 ExplicitlyTypedAddress::Fqdn {
183 address_type: a1,
184 domain: d1,
185 },
186 ExplicitlyTypedAddress::Fqdn {
187 address_type: a2,
188 domain: d2,
189 },
190 ) => a1 == a2 && d1.to_lowercase() == d2.to_lowercase(),
191 (ExplicitlyTypedAddress::Ip(a), ExplicitlyTypedAddress::Ip(b)) => a == b,
192 (_, _) => false,
193 }
194 }
195}
196
197#[cfg(test)]
198#[path = "./address_tests.rs"]
199mod address_tests;