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}
152