async_uninet/
socket_addr.rs

1use std::fmt;
2use std::str::FromStr;
3use std::path::{Path, PathBuf};
4use async_std::net::ToSocketAddrs;
5use async_std::net;
6#[cfg(unix)]
7use async_std::os::unix::net as unix;
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10pub enum SocketAddr {
11    Inet(net::SocketAddr),
12    #[cfg(unix)]
13    Unix(PathBuf)
14}
15
16impl From<net::SocketAddr> for SocketAddr {
17    fn from(s: net::SocketAddr) -> SocketAddr {
18        SocketAddr::Inet(s)
19    }
20}
21
22#[cfg(unix)]
23impl From<unix::SocketAddr> for SocketAddr {
24    fn from(s: unix::SocketAddr) -> SocketAddr {
25        SocketAddr::Unix(match s.as_pathname() {
26            None => Path::new(".sock").to_path_buf(),
27            Some(p) => p.to_path_buf()
28        })
29    }
30}
31
32impl fmt::Display for SocketAddr {
33    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34        match self {
35            SocketAddr::Inet(n) => write!(f, "{}", n),
36            #[cfg(unix)]
37            SocketAddr::Unix(n) => write!(f, "unix:{}", n.to_string_lossy())
38        }
39    }
40}
41
42impl FromStr for SocketAddr {
43    type Err = net::AddrParseError;
44
45    #[cfg(unix)]
46    fn from_str(s: &str) -> Result<SocketAddr, net::AddrParseError> {
47        if s.starts_with("unix:") {
48            Ok(SocketAddr::Unix(Path::new(s.trim_start_matches("unix:")).to_path_buf()))
49        } else {
50            s.parse().map(SocketAddr::Inet)
51        }
52    }
53
54    #[cfg(not(unix))]
55    fn from_str(s: &str) -> Result<SocketAddr, net::AddrParseError> {
56        s.parse().map(SocketAddr::Inet)
57    }
58}
59
60impl SocketAddr {
61
62    pub async fn from_str<S: Into<String>>(txt: S) -> Result<Self, ()> {
63        let txt = txt.into();
64        if txt.starts_with("unix:") {
65            let addr = match txt.parse::<Self>() {
66                Ok(addr) => addr,
67                Err(_) => return Err(()),
68            };
69            Ok(Self::from(addr))
70        } else {
71            let addr = match txt.to_socket_addrs().await {
72                Err(_) => return Err(()),
73                Ok(mut addr) => match addr.next() {
74                    Some(addr) => addr,
75                    None => return Err(()),
76                },
77            };
78            Ok(Self::from(addr))
79        }
80    }
81
82    pub fn is_unix(&self) -> bool {
83        match self {
84            #[cfg(unix)]
85            SocketAddr::Unix(_) => true,
86            _ => false,
87        }
88    }
89
90    pub fn is_inet(&self) -> bool {
91        !self.is_unix()
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    #[async_std::test]
100    async fn creates_from_inet() {
101        let ip4 = SocketAddr::from_str("127.0.0.1:10").await;
102        let ip6 = SocketAddr::from_str("[::20]:10").await;
103        let url = SocketAddr::from_str("jsonplaceholder.typicode.com:80").await;
104        let invalid = SocketAddr::from_str("foo").await;
105        assert!(ip4.is_ok());
106        assert!(ip6.is_ok());
107        assert!(url.is_ok());
108        assert!(invalid.is_err());
109        assert_eq!(ip4.unwrap().to_string(), "127.0.0.1:10");
110        assert_eq!(ip6.unwrap().to_string(), "[::0.0.0.32]:10");
111        assert!(url.unwrap().to_string().starts_with("104.")); // 104.28.28.222:80, 104.28.29.222:80
112    }
113
114    #[async_std::test]
115    #[cfg(unix)]
116    async fn creates_from_unix() {
117        let unix = SocketAddr::from_str("unix:/tmp/sock").await;
118        let invalid = SocketAddr::from_str("/tmp/sock").await;
119        assert!(unix.is_ok());
120        assert!(invalid.is_err());
121    }
122}