use crate::{utils::ipv6_with_scope_id, Domain};
#[derive(
Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, serde::Serialize, serde::Deserialize,
)]
#[serde(untagged)]
pub enum Target {
Domain(Domain),
Ip(std::net::IpAddr),
Socket(std::net::SocketAddr),
}
impl Default for Target {
#[inline]
fn default() -> Self {
Self::Domain(Domain::default())
}
}
impl std::str::FromStr for Target {
type Err = anyhow::Error;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.find('%').map_or_else(
|| {
s.parse::<std::net::SocketAddr>().map_or_else(
|_| {
s.parse::<std::net::IpAddr>().map_or_else(
|_| {
Domain::from_utf8(s).map(Self::Domain).map_err(|err| {
anyhow::anyhow!("{err} could not be used as a forward target.",)
})
},
|ip| Ok(Self::Ip(ip)),
)
},
|socket| Ok(Self::Socket(socket)),
)
},
|_| ipv6_with_scope_id(s).map(Self::Socket),
)
}
}
impl std::fmt::Display for Target {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Domain(domain) => write!(f, "{domain}"),
Self::Ip(ip) => write!(f, "{ip}"),
Self::Socket(socket) => write!(f, "{socket}"),
}
}
}