async_uninet/
socket_addr.rs1use 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.")); }
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}