1use core::fmt;
43use core::str::FromStr;
44use std::net::SocketAddr;
45use std::path::PathBuf;
46
47use http::Uri;
48
49#[derive(Clone, Debug, PartialEq, Eq)]
50pub enum ListenAddress {
51 Network(SocketAddr),
52 UnixSocket(PathBuf),
53}
54
55#[derive(Clone, Debug, PartialEq, Eq)]
56pub enum ConnectAddress {
57 Uri(Uri),
58 UnixSocket(PathBuf),
59}
60
61impl FromStr for ListenAddress {
62 type Err = Error;
63
64 fn from_str(s: &str) -> Result<Self, Self::Err> {
65 match s.strip_prefix("unix:") {
66 Some(v) => Ok(Self::UnixSocket(v.into())),
67 None => match SocketAddr::from_str(s) {
68 Ok(v) => Ok(Self::Network(v)),
69 Err(_) => Err(Error::InvalidListenAddress(s.to_owned())),
70 },
71 }
72 }
73}
74
75impl fmt::Display for ListenAddress {
76 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
77 match self {
78 Self::Network(addr) => addr.fmt(f),
79 Self::UnixSocket(path) => {
80 f.write_str("unix:")?;
81 path.display().fmt(f)
82 },
83 }
84 }
85}
86
87impl FromStr for ConnectAddress {
88 type Err = Error;
89
90 fn from_str(s: &str) -> Result<Self, Self::Err> {
91 match s.strip_prefix("unix:") {
92 Some(v) => Ok(Self::UnixSocket(v.into())),
93 None => Ok(Self::Uri(Uri::from_str(s)?)),
94 }
95 }
96}
97
98impl fmt::Display for ConnectAddress {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
100 match self {
101 Self::UnixSocket(path) => {
102 f.write_str("unix:")?;
103 path.display().fmt(f)
104 },
105 Self::Uri(uri) => uri.fmt(f),
106 }
107 }
108}
109
110impl TryFrom<ConnectAddress> for ListenAddress {
111 type Error = Error;
112
113 fn try_from(value: ConnectAddress) -> Result<Self, Self::Error> {
114 Ok(match value {
115 ConnectAddress::Uri(uri) => {
116 let no_scheme = format!("{}:{}", uri.host().ok_or(Error::MissingHost)?, uri.port().ok_or(Error::MissingPort)?);
117 Self::Network(SocketAddr::from_str(&no_scheme).map_err(|_| Error::InvalidListenAddress(no_scheme))?)
118 },
119 ConnectAddress::UnixSocket(path) => Self::UnixSocket(path),
120 })
121 }
122}
123
124#[derive(Debug, thiserror::Error)]
125pub enum Error {
126 #[error("'{0}' is neither a valid IP:port address nor a path prefixed with 'unix:'")]
127 InvalidListenAddress(String),
128
129 #[error("String has a scheme prefix of either http or https but could not be parsed into a Uri: {0}")]
130 InvalidUri(#[from] http::uri::InvalidUri),
131
132 #[error("The address is missing a host")]
133 MissingHost,
134
135 #[error("The address is missing a port")]
136 MissingPort,
137}