1use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
2use std::{
3 fmt,
4 net::{IpAddr, SocketAddr},
5 str::FromStr,
6};
7
8#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
9pub enum PeerPort {
10 Tcp(u16),
11 Quic(u16),
12}
13
14#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
15pub enum PeerAddr {
16 Tcp(SocketAddr),
17 Quic(SocketAddr),
18}
19
20impl PeerAddr {
21 pub fn socket_addr(&self) -> &SocketAddr {
22 match self {
23 Self::Tcp(addr) => addr,
24 Self::Quic(addr) => addr,
25 }
26 }
27
28 pub fn ip(&self) -> IpAddr {
29 self.socket_addr().ip()
30 }
31
32 pub fn port(&self) -> u16 {
33 self.socket_addr().port()
34 }
35
36 pub fn set_port(&mut self, port: u16) {
37 match self {
38 Self::Tcp(addr) => addr.set_port(port),
39 Self::Quic(addr) => addr.set_port(port),
40 }
41 }
42
43 pub fn peer_port(&self) -> PeerPort {
44 match self {
45 Self::Tcp(addr) => PeerPort::Tcp(addr.port()),
46 Self::Quic(addr) => PeerPort::Quic(addr.port()),
47 }
48 }
49
50 pub fn is_quic(&self) -> bool {
51 match self {
52 Self::Tcp(_) => false,
53 Self::Quic(_) => true,
54 }
55 }
56
57 pub fn is_tcp(&self) -> bool {
58 match self {
59 Self::Tcp(_) => true,
60 Self::Quic(_) => false,
61 }
62 }
63}
64
65impl FromStr for PeerAddr {
66 type Err = String;
67
68 fn from_str(s: &str) -> Result<Self, Self::Err> {
69 let (proto, addr) = match s.split_once('/') {
70 Some((proto, addr)) => (proto, addr),
71 None => {
72 return Err(format!(
73 "Could not find '/' delimiter in the address {s:?}"
74 ));
75 }
76 };
77
78 let addr = match SocketAddr::from_str(addr) {
79 Ok(addr) => addr,
80 Err(_) => return Err(format!("Failed to parse IP:PORT {addr:?}")),
81 };
82
83 if proto.eq_ignore_ascii_case("tcp") {
84 Ok(PeerAddr::Tcp(addr))
85 } else if proto.eq_ignore_ascii_case("quic") {
86 Ok(PeerAddr::Quic(addr))
87 } else {
88 Err(format!("Unrecognized protocol {proto:?} in {s:?}"))
89 }
90 }
91}
92
93impl fmt::Display for PeerAddr {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 match self {
96 Self::Tcp(addr) => write!(f, "tcp/{addr}"),
97 Self::Quic(addr) => write!(f, "quic/{addr}"),
98 }
99 }
100}
101
102impl Serialize for PeerAddr {
103 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
104 where
105 S: Serializer,
106 {
107 if s.is_human_readable() {
108 self.to_string().serialize(s)
109 } else {
110 SerdeProxy::serialize(self, s)
111 }
112 }
113}
114
115impl<'de> Deserialize<'de> for PeerAddr {
116 fn deserialize<D>(d: D) -> Result<Self, D::Error>
117 where
118 D: Deserializer<'de>,
119 {
120 if d.is_human_readable() {
121 <&str>::deserialize(d)?.parse().map_err(D::Error::custom)
122 } else {
123 SerdeProxy::deserialize(d)
124 }
125 }
126}
127
128#[derive(Serialize, Deserialize)]
130#[serde(remote = "PeerAddr")]
131enum SerdeProxy {
132 Tcp(#[allow(dead_code)] SocketAddr),
133 Quic(#[allow(dead_code)] SocketAddr),
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139 use std::net::{Ipv4Addr, Ipv6Addr};
140
141 #[test]
142 fn parse() {
143 for (orig, expected) in [
144 (
145 PeerAddr::Tcp((Ipv4Addr::UNSPECIFIED, 0).into()),
146 "tcp/0.0.0.0:0",
147 ),
148 (
149 PeerAddr::Tcp((Ipv6Addr::UNSPECIFIED, 0).into()),
150 "tcp/[::]:0",
151 ),
152 (
153 PeerAddr::Quic((Ipv4Addr::UNSPECIFIED, 0).into()),
154 "quic/0.0.0.0:0",
155 ),
156 (
157 PeerAddr::Quic((Ipv6Addr::UNSPECIFIED, 0).into()),
158 "quic/[::]:0",
159 ),
160 ] {
161 assert_eq!(orig.to_string(), expected);
162 assert_eq!(expected.parse::<PeerAddr>().unwrap(), orig);
163 }
164 }
165
166 #[test]
167 fn serialize_binary() {
168 for (orig, expected) in [
169 (
170 PeerAddr::Tcp(([192, 0, 2, 0], 12481).into()),
171 "0000000000000000c0000200c130",
172 ),
173 (
174 PeerAddr::Quic(([0x2001, 0xdb8, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5], 24816).into()),
175 "010000000100000020010db8000000010002000300040005f060",
176 ),
177 ] {
178 assert_eq!(hex::encode(bincode::serialize(&orig).unwrap()), expected);
179 assert_eq!(
180 bincode::deserialize::<PeerAddr>(&hex::decode(expected).unwrap()).unwrap(),
181 orig
182 );
183 }
184 }
185
186 #[test]
187 fn serialize_human_readable() {
188 for addr in [
189 PeerAddr::Tcp(([192, 0, 2, 0], 12481).into()),
190 PeerAddr::Quic(([0x2001, 0xdb8, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5], 24816).into()),
191 ] {
192 let expected = addr.to_string();
193 let actual = serde_json::to_string(&addr).unwrap();
194 assert_eq!(actual, format!("\"{expected}\""))
195 }
196 }
197}