use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
use crate::{AddrParseError, Host, Localhost};
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display, From)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[display(inner)]
#[cfg(feature = "dns")]
pub enum InetHost {
#[from]
#[from(Ipv4Addr)]
#[from(Ipv6Addr)]
Ip(IpAddr),
Dns(String),
}
#[cfg(feature = "dns")]
impl Host for InetHost {
fn requires_proxy(&self) -> bool { false }
}
#[cfg(feature = "dns")]
impl Localhost for InetHost {
fn localhost() -> Self { Self::Ip(Localhost::localhost()) }
}
#[cfg(feature = "dns")]
impl FromStr for InetHost {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match IpAddr::from_str(s) {
Ok(addr) => Ok(Self::Ip(addr)),
Err(_) => Ok(Self::Dns(s.to_owned())),
}
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, Display, From)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[display(inner)]
#[non_exhaustive]
pub enum HostName {
#[from]
#[from(Ipv4Addr)]
#[from(Ipv6Addr)]
Ip(IpAddr),
#[cfg(feature = "dns")]
Dns(String),
#[cfg(feature = "tor")]
#[from]
Tor(super::tor::OnionAddrV3),
#[cfg(feature = "i2p")]
#[from]
I2p(super::i2p::I2pAddr),
#[cfg(feature = "nym")]
#[from]
Nym(super::nym::NymAddr),
}
impl Host for HostName {
fn requires_proxy(&self) -> bool {
match self {
HostName::Ip(_) => false,
#[cfg(feature = "dns")]
HostName::Dns(_) => false,
#[allow(unreachable_patterns)]
_ => true,
}
}
}
impl Localhost for HostName {
fn localhost() -> Self { Self::Ip(Localhost::localhost()) }
}
#[cfg(feature = "dns")]
impl From<InetHost> for HostName {
fn from(host: InetHost) -> Self {
match host {
InetHost::Ip(ip) => HostName::Ip(ip),
InetHost::Dns(dns) => HostName::Dns(dns),
}
}
}
impl FromStr for HostName {
type Err = AddrParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(addr) = IpAddr::from_str(s) {
return Ok(Self::Ip(addr));
}
#[cfg(feature = "tor")]
if s.ends_with(".onion") {
return super::tor::OnionAddrV3::from_str(s)
.map(Self::Tor)
.map_err(AddrParseError::from);
}
#[cfg(feature = "i2p")]
if super::i2p::ends_with_suffix(s) {
return super::i2p::I2pAddr::from_str(s).map(Self::I2p).map_err(AddrParseError::from);
}
#[cfg(feature = "dns")]
{
Ok(Self::Dns(s.to_owned()))
}
#[cfg(not(feature = "dns"))]
{
Err(AddrParseError::UnknownAddressFormat)
}
}
}