1use std::fmt;
2
3use super::{ErrorKind, InvalidUri};
4
5pub struct Port<T> {
7    port: u16,
8    repr: T,
9}
10
11impl<T> Port<T> {
12    pub const fn as_u16(&self) -> u16 {
26        self.port
27    }
28}
29
30impl<T> Port<T>
31where
32    T: AsRef<str>,
33{
34    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    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        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        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}