use core::fmt::Display;
use net_types::ip::{GenericOverIp, Ip, IpAddress, Ipv4Addr, Ipv6Addr, Ipv6SourceAddr};
use net_types::{NonMappedAddr, NonMulticastAddr, SpecifiedAddr, UnicastAddr, Witness as _};
use crate::socket::SocketIpAddr;
#[derive(Copy, Clone, Debug, Eq, GenericOverIp, Hash, PartialEq)]
#[generic_over_ip(A, IpAddress)]
pub struct IpDeviceAddr<A: IpAddress>(NonMulticastAddr<NonMappedAddr<SpecifiedAddr<A>>>);
impl<A: IpAddress> Display for IpDeviceAddr<A> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let Self(addr) = self;
write!(f, "{}", addr)
}
}
impl<A: IpAddress> IpDeviceAddr<A> {
pub fn addr(self) -> A {
let Self(addr) = self;
***addr
}
pub fn into_inner(self) -> NonMulticastAddr<NonMappedAddr<SpecifiedAddr<A>>> {
let IpDeviceAddr(addr) = self;
addr
}
pub fn new(addr: A) -> Option<IpDeviceAddr<A>> {
Some(IpDeviceAddr(NonMulticastAddr::new(NonMappedAddr::new(SpecifiedAddr::new(addr)?)?)?))
}
pub fn new_from_witness(addr: NonMulticastAddr<NonMappedAddr<SpecifiedAddr<A>>>) -> Self {
Self(addr)
}
pub fn new_from_socket_ip_addr(addr: SocketIpAddr<A>) -> Option<Self> {
NonMulticastAddr::new(addr.into_inner()).map(Self)
}
}
impl IpDeviceAddr<Ipv6Addr> {
pub fn new_from_ipv6_device_addr(addr: Ipv6DeviceAddr) -> Self {
let addr: UnicastAddr<NonMappedAddr<Ipv6Addr>> = addr.transpose();
let addr: NonMappedAddr<SpecifiedAddr<Ipv6Addr>> = addr.into_specified().transpose();
let addr = unsafe { NonMulticastAddr::new_unchecked(addr) };
Self(addr)
}
pub fn new_from_ipv6_source(addr: Ipv6SourceAddr) -> Option<Self> {
match addr {
Ipv6SourceAddr::Unicast(addr) => Some(Self::new_from_ipv6_device_addr(addr)),
Ipv6SourceAddr::Unspecified => None,
}
}
}
impl<A: IpAddress> From<IpDeviceAddr<A>> for SpecifiedAddr<A> {
fn from(addr: IpDeviceAddr<A>) -> Self {
**addr.into_inner()
}
}
impl<A: IpAddress> AsRef<SpecifiedAddr<A>> for IpDeviceAddr<A> {
fn as_ref(&self) -> &SpecifiedAddr<A> {
let Self(addr) = self;
addr.as_ref()
}
}
impl<A: IpAddress> From<IpDeviceAddr<A>> for SocketIpAddr<A> {
fn from(addr: IpDeviceAddr<A>) -> Self {
SocketIpAddr::new_from_witness(*addr.into_inner())
}
}
#[derive(Debug)]
pub enum IpDeviceAddrError {
NotNonMapped,
NotNonMulticast,
}
impl<A: IpAddress> TryFrom<SpecifiedAddr<A>> for IpDeviceAddr<A> {
type Error = IpDeviceAddrError;
fn try_from(addr: SpecifiedAddr<A>) -> Result<Self, Self::Error> {
Ok(IpDeviceAddr::new_from_witness(
NonMulticastAddr::new(NonMappedAddr::new(addr).ok_or(IpDeviceAddrError::NotNonMapped)?)
.ok_or(IpDeviceAddrError::NotNonMulticast)?,
))
}
}
pub type Ipv4DeviceAddr = NonMulticastAddr<NonMappedAddr<SpecifiedAddr<Ipv4Addr>>>;
pub type Ipv6DeviceAddr = NonMappedAddr<UnicastAddr<Ipv6Addr>>;