Skip to main content

trillium_server_common/listener_config/
into_listen_addr.rs

1use std::{
2    fmt::Display,
3    io,
4    net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs},
5};
6
7/// Conversion into a single TCP bind address.
8///
9/// Implemented for the address-shaped inputs — a bare port (binds `0.0.0.0:port`), a [`SocketAddr`]
10/// or its v4/v6 forms, and `(ip, port)` tuples — all of which are infallible, and for the string
11/// and `(host, port)` forms, which are resolved through the system resolver and so can fail or
12/// yield no address. A resolving form binds the *first* address it resolves to; pass a
13/// [`SocketAddr`] when you need to pin exactly which one.
14pub trait IntoListenAddr {
15    /// Resolve to the concrete socket address to bind, surfacing a resolution failure as an
16    /// [`io::Error`].
17    fn into_listen_addr(self) -> io::Result<SocketAddr>;
18}
19
20/// Resolve through [`ToSocketAddrs`] and take the first address, reporting an empty resolution as
21/// an error that names what failed to resolve.
22fn resolve_first(addr: impl ToSocketAddrs, label: impl Display) -> io::Result<SocketAddr> {
23    addr.to_socket_addrs()?
24        .next()
25        .ok_or_else(|| io::Error::other(format!("`{label}` did not resolve to a bind address")))
26}
27
28impl IntoListenAddr for SocketAddr {
29    fn into_listen_addr(self) -> io::Result<SocketAddr> {
30        Ok(self)
31    }
32}
33
34impl IntoListenAddr for SocketAddrV4 {
35    fn into_listen_addr(self) -> io::Result<SocketAddr> {
36        Ok(self.into())
37    }
38}
39
40impl IntoListenAddr for SocketAddrV6 {
41    fn into_listen_addr(self) -> io::Result<SocketAddr> {
42        Ok(self.into())
43    }
44}
45
46impl IntoListenAddr for u16 {
47    fn into_listen_addr(self) -> io::Result<SocketAddr> {
48        Ok(SocketAddr::from((Ipv4Addr::UNSPECIFIED, self)))
49    }
50}
51
52impl IntoListenAddr for (IpAddr, u16) {
53    fn into_listen_addr(self) -> io::Result<SocketAddr> {
54        Ok(SocketAddr::from(self))
55    }
56}
57
58impl IntoListenAddr for (Ipv4Addr, u16) {
59    fn into_listen_addr(self) -> io::Result<SocketAddr> {
60        Ok(SocketAddr::from(self))
61    }
62}
63
64impl IntoListenAddr for (Ipv6Addr, u16) {
65    fn into_listen_addr(self) -> io::Result<SocketAddr> {
66        Ok(SocketAddr::from(self))
67    }
68}
69
70impl IntoListenAddr for &str {
71    fn into_listen_addr(self) -> io::Result<SocketAddr> {
72        resolve_first(self, self)
73    }
74}
75
76impl IntoListenAddr for String {
77    fn into_listen_addr(self) -> io::Result<SocketAddr> {
78        resolve_first(&self, &self)
79    }
80}
81
82impl IntoListenAddr for (&str, u16) {
83    fn into_listen_addr(self) -> io::Result<SocketAddr> {
84        resolve_first(self, format!("{}:{}", self.0, self.1))
85    }
86}