http/uri/
port.rs

1use std::fmt;
2
3use super::{ErrorKind, InvalidUri};
4
5/// The port component of a URI.
6pub struct Port<T> {
7    port: u16,
8    repr: T,
9}
10
11impl<T> Port<T> {
12    /// Returns the port number as a `u16`.
13    ///
14    /// # Examples
15    ///
16    /// Port as `u16`.
17    ///
18    /// ```
19    /// # use http::uri::Authority;
20    /// let authority: Authority = "example.org:80".parse().unwrap();
21    ///
22    /// let port = authority.port().unwrap();
23    /// assert_eq!(port.as_u16(), 80);
24    /// ```
25    pub fn as_u16(&self) -> u16 {
26        self.port
27    }
28}
29
30impl<T> Port<T>
31where
32    T: AsRef<str>,
33{
34    /// Converts a `str` to a port number.
35    ///
36    /// The supplied `str` must be a valid u16.
37    pub(crate) fn from_str(bytes: T) -> Result<Self, InvalidUri> {
38        bytes
39            .as_ref()
40            .parse::<u16>()
41            .map(|port| Port { port, repr: bytes })
42            .map_err(|_| ErrorKind::InvalidPort.into())
43    }
44
45    /// Returns the port number as a `str`.
46    ///
47    /// # Examples
48    ///
49    /// Port as `str`.
50    ///
51    /// ```
52    /// # use http::uri::Authority;
53    /// let authority: Authority = "example.org:80".parse().unwrap();
54    ///
55    /// let port = authority.port().unwrap();
56    /// assert_eq!(port.as_str(), "80");
57    /// ```
58    pub fn as_str(&self) -> &str {
59        self.repr.as_ref()
60    }
61}
62
63impl<T> fmt::Debug for Port<T>
64where
65    T: fmt::Debug,
66{
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        f.debug_tuple("Port").field(&self.port).finish()
69    }
70}
71
72impl<T> fmt::Display for Port<T> {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        // Use `u16::fmt` so that it respects any formatting flags that
75        // may have been set (like padding, align, etc).
76        fmt::Display::fmt(&self.port, f)
77    }
78}
79
80impl<T> From<Port<T>> for u16 {
81    fn from(port: Port<T>) -> Self {
82        port.as_u16()
83    }
84}
85
86impl<T> AsRef<str> for Port<T>
87where
88    T: AsRef<str>,
89{
90    fn as_ref(&self) -> &str {
91        self.as_str()
92    }
93}
94
95impl<T, U> PartialEq<Port<U>> for Port<T> {
96    fn eq(&self, other: &Port<U>) -> bool {
97        self.port == other.port
98    }
99}
100
101impl<T> PartialEq<u16> for Port<T> {
102    fn eq(&self, other: &u16) -> bool {
103        self.port == *other
104    }
105}
106
107impl<T> PartialEq<Port<T>> for u16 {
108    fn eq(&self, other: &Port<T>) -> bool {
109        other.port == *self
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn partialeq_port() {
119        let port_a = Port::from_str("8080").unwrap();
120        let port_b = Port::from_str("8080").unwrap();
121        assert_eq!(port_a, port_b);
122    }
123
124    #[test]
125    fn partialeq_port_different_reprs() {
126        let port_a = Port {
127            repr: "8081",
128            port: 8081,
129        };
130        let port_b = Port {
131            repr: String::from("8081"),
132            port: 8081,
133        };
134        assert_eq!(port_a, port_b);
135        assert_eq!(port_b, port_a);
136    }
137
138    #[test]
139    fn partialeq_u16() {
140        let port = Port::from_str("8080").unwrap();
141        // test equals in both directions
142        assert_eq!(port, 8080);
143        assert_eq!(8080, port);
144    }
145
146    #[test]
147    fn u16_from_port() {
148        let port = Port::from_str("8080").unwrap();
149        assert_eq!(8080, u16::from(port));
150    }
151}