std::ne::Ipv6Addr is currently unable to parse IPv6 addresses with a scope identifier, like FE80::C001:1DFF:FEE0:0%eth0, as defined in RFC 4007. It is possible to work around that limitation by using something like:
use std::net::{Ipv4Addr, Ipv6Addr};
pub enum Ip {
V4(Ipv4Addr),
V6(Ipv6Addr, Option<String>),
}
And then implement FromStr for Ip.
But it's pretty inconvenient, and I'd rather use std::net::IpAddr. Would it be possible to support this directly in std::net::Ipv6Addr? If so, what is the right path to make this happen? Open an issue on github?
Even if you could somehow maintain the Copy aspect, it’s likely you wouldn’t want to waste any space on a (AFAICT) rarely specified part of the address. To that end, a custom type (whether in std or otherwise) seems more appropriate anyway.
That makes sense.
I created a custom type like this, for now:
use std::net::{Ipv4Addr, Ipv6Addr};
/// Represent an IP address. This type is similar to `std::net::IpAddr` but it supports IPv6 scope
/// identifiers.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Ip {
/// Represent an IPv4 address
V4(Ipv4Addr),
/// Represent an IPv6 and its scope identifier, if any
V6(Ipv6Addr, Option<String>),
}
impl Into<IpAddr> for Ip {
fn into(self) -> IpAddr {
match self {
Ip::V4(ip) => IpAddr::from(ip),
Ip::V6(ip, _) => IpAddr::from(ip),
}
}
}
impl From<Ipv6Addr> for Ip {
fn from(value: Ipv6Addr) -> Self {
Ip::V6(value, None)
}
}
impl From<Ipv4Addr> for Ip {
fn from(value: Ipv4Addr) -> Self {
Ip::V4(value)
}
}
impl From<IpAddr> for Ip {
fn from(value: IpAddr) -> Self {
match value {
IpAddr::V4(ip) => Ip::from(ip),
IpAddr::V6(ip) => Ip::from(ip),
}
}
}
impl Ip {
/// Parse a string representing an IP address.
pub fn parse(s: &str) -> Result<Ip, AddrParseError> {
let mut parts = s.split('%');
let addr = parts.next().unwrap();
match IpAddr::from_str(addr) {
Ok(IpAddr::V4(ip)) => Ok(Ip::from(ip)),
Ok(IpAddr::V6(ip)) => Ok(Ip::V6(ip, parts.next().map(|s| s.to_string()))),
Err(e) => Err(e),
}
}