use crate::conn::Conn;
use crate::extended::Extended;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
const V4MAPPED_LO: u128 = 0x0000_0000_0000_0000_0000_FFFF_0000_0000;
const V4MAPPED_HI: u128 = 0x0000_0000_0000_0000_0000_FFFF_FFFF_FFFF;
const fn u32_to_v4(b: u32) -> Ipv4Addr {
Ipv4Addr::from_bits(b)
}
const fn v4_to_u32(a: Ipv4Addr) -> u32 {
a.to_bits()
}
crate::iso! {
pub U032IPV4 : u32 => Ipv4Addr {
forward: u32_to_v4,
back: v4_to_u32,
}
}
const fn u128_to_v6(b: u128) -> Ipv6Addr {
Ipv6Addr::from_bits(b)
}
const fn v6_to_u128(a: Ipv6Addr) -> u128 {
a.to_bits()
}
crate::iso! {
pub U128IPV6 : u128 => Ipv6Addr {
forward: u128_to_v6,
back: v6_to_u128,
}
}
const fn ipv6ipv4_ceil(v6: Ipv6Addr) -> Extended<Ipv4Addr> {
let bits = v6.to_bits();
if bits == 0 {
Extended::NegInf
} else if bits < V4MAPPED_LO {
Extended::Finite(Ipv4Addr::UNSPECIFIED)
} else if bits <= V4MAPPED_HI {
Extended::Finite(Ipv4Addr::from_bits(bits as u32))
} else {
Extended::PosInf
}
}
const fn ipv6ipv4_inner(b: Extended<Ipv4Addr>) -> Ipv6Addr {
match b {
Extended::NegInf => Ipv6Addr::UNSPECIFIED,
Extended::Finite(v4) => v4.to_ipv6_mapped(),
Extended::PosInf => Ipv6Addr::from_bits(u128::MAX),
}
}
const fn ipv6ipv4_floor(v6: Ipv6Addr) -> Extended<Ipv4Addr> {
let bits = v6.to_bits();
if bits == u128::MAX {
Extended::PosInf
} else if bits < V4MAPPED_LO {
Extended::NegInf
} else if bits <= V4MAPPED_HI {
Extended::Finite(Ipv4Addr::from_bits(bits as u32))
} else {
Extended::Finite(Ipv4Addr::BROADCAST)
}
}
crate::conn_k! {
pub IPV6IPV4 : Ipv6Addr => Extended<Ipv4Addr> {
ceil: ipv6ipv4_ceil,
inner: ipv6ipv4_inner,
floor: ipv6ipv4_floor,
}
}
pub const IPVXIPV4: crate::conn::Conn<IpAddr, Extended<Ipv4Addr>> = {
fn ceil(a: IpAddr) -> Extended<Ipv4Addr> {
match a {
IpAddr::V4(v4) if v4 == Ipv4Addr::UNSPECIFIED => Extended::NegInf,
IpAddr::V4(v4) => Extended::Finite(v4),
IpAddr::V6(_) => Extended::PosInf,
}
}
fn inner(b: Extended<Ipv4Addr>) -> IpAddr {
match b {
Extended::NegInf => IpAddr::V4(Ipv4Addr::UNSPECIFIED),
Extended::Finite(v4) => IpAddr::V4(v4),
Extended::PosInf => IpAddr::V6(Ipv6Addr::from_bits(u128::MAX)),
}
}
Conn::new_l(ceil, inner)
};
pub const IPVXIPV6: crate::conn::Conn<IpAddr, Extended<Ipv6Addr>, crate::conn::R> = {
fn inner(b: Extended<Ipv6Addr>) -> IpAddr {
match b {
Extended::NegInf => IpAddr::V4(Ipv4Addr::UNSPECIFIED),
Extended::Finite(v6) => IpAddr::V6(v6),
Extended::PosInf => IpAddr::V6(Ipv6Addr::from_bits(u128::MAX)),
}
}
fn floor(a: IpAddr) -> Extended<Ipv6Addr> {
match a {
IpAddr::V4(_) => Extended::NegInf,
IpAddr::V6(v6) if v6.to_bits() == u128::MAX => Extended::PosInf,
IpAddr::V6(v6) => Extended::Finite(v6),
}
}
Conn::new_r(inner, floor)
};
#[cfg(test)]
mod tests {
use super::*;
#[allow(unused_imports)]
use crate::conn::{ConnL, ConnR};
use crate::prop::arb::{arb_extended_ipv4, arb_extended_ipv6, arb_ip_addr, arb_ipv4, arb_ipv6};
use crate::prop::conn as conn_laws;
use proptest::prelude::*;
#[test]
fn u032ipv4_loopback() {
assert_eq!(
U032IPV4.view_l().ceil(0x7F000001_u32),
Ipv4Addr::new(127, 0, 0, 1)
);
assert_eq!(
U032IPV4.view_l().upper(Ipv4Addr::new(127, 0, 0, 1)),
0x7F000001_u32
);
}
#[test]
fn u032ipv4_extremes() {
assert_eq!(U032IPV4.view_l().ceil(0_u32), Ipv4Addr::UNSPECIFIED);
assert_eq!(U032IPV4.view_l().ceil(u32::MAX), Ipv4Addr::BROADCAST);
assert_eq!(U032IPV4.view_l().upper(Ipv4Addr::UNSPECIFIED), 0_u32);
assert_eq!(U032IPV4.view_l().upper(Ipv4Addr::BROADCAST), u32::MAX);
}
#[test]
fn u128ipv6_localhost() {
assert_eq!(U128IPV6.view_l().ceil(1_u128), Ipv6Addr::LOCALHOST);
assert_eq!(U128IPV6.view_l().upper(Ipv6Addr::LOCALHOST), 1_u128);
}
#[test]
fn u128ipv6_extremes() {
assert_eq!(U128IPV6.view_l().ceil(0_u128), Ipv6Addr::UNSPECIFIED);
assert_eq!(U128IPV6.view_l().upper(Ipv6Addr::UNSPECIFIED), 0_u128);
assert_eq!(
U128IPV6.view_l().ceil(u128::MAX),
Ipv6Addr::from_bits(u128::MAX)
);
}
crate::law_battery! {
mod u032ipv4_laws,
conn: U032IPV4,
fine: any::<u32>(),
coarse: arb_ipv4(),
}
crate::law_battery! {
mod u128ipv6_laws,
conn: U128IPV6,
fine: any::<u128>(),
coarse: arb_ipv6(),
}
proptest! {
#[test]
fn u032ipv4_floor_le_ceil(b in any::<u32>()) {
prop_assert!(conn_laws::floor_le_ceil(&U032IPV4, b));
}
#[test]
fn u128ipv6_floor_le_ceil(b in any::<u128>()) {
prop_assert!(conn_laws::floor_le_ceil(&U128IPV6, b));
}
}
#[test]
fn ipv6ipv4_v4mapped_round_trip() {
let v4 = Ipv4Addr::new(127, 0, 0, 1);
let v6: Ipv6Addr = "::ffff:7f00:1".parse().unwrap();
assert_eq!(IPV6IPV4.view_l().ceil(v6), Extended::Finite(v4));
assert_eq!(IPV6IPV4.view_r().floor(v6), Extended::Finite(v4));
assert_eq!(IPV6IPV4.view_l().upper(Extended::Finite(v4)), v6);
}
#[test]
fn ipv6ipv4_v4mapped_extremes() {
let lo = Ipv6Addr::from_bits(V4MAPPED_LO);
let hi = Ipv6Addr::from_bits(V4MAPPED_HI);
assert_eq!(
IPV6IPV4.view_l().ceil(lo),
Extended::Finite(Ipv4Addr::UNSPECIFIED)
);
assert_eq!(
IPV6IPV4.view_r().floor(lo),
Extended::Finite(Ipv4Addr::UNSPECIFIED)
);
assert_eq!(
IPV6IPV4.view_l().ceil(hi),
Extended::Finite(Ipv4Addr::BROADCAST)
);
assert_eq!(
IPV6IPV4.view_r().floor(hi),
Extended::Finite(Ipv4Addr::BROADCAST)
);
}
#[test]
fn ipv6ipv4_below_block_asymmetric() {
assert_eq!(
IPV6IPV4.view_l().ceil(Ipv6Addr::LOCALHOST),
Extended::Finite(Ipv4Addr::UNSPECIFIED)
);
assert_eq!(
IPV6IPV4.view_r().floor(Ipv6Addr::LOCALHOST),
Extended::NegInf
);
let just_below = Ipv6Addr::from_bits(V4MAPPED_LO - 1);
assert_eq!(
IPV6IPV4.view_l().ceil(just_below),
Extended::Finite(Ipv4Addr::UNSPECIFIED)
);
assert_eq!(IPV6IPV4.view_r().floor(just_below), Extended::NegInf);
}
#[test]
fn ipv6ipv4_above_block_asymmetric() {
let just_above = Ipv6Addr::from_bits(V4MAPPED_HI + 1);
assert_eq!(IPV6IPV4.view_l().ceil(just_above), Extended::PosInf);
assert_eq!(
IPV6IPV4.view_r().floor(just_above),
Extended::Finite(Ipv4Addr::BROADCAST)
);
}
#[test]
fn ipv6ipv4_ipv6_extremes_synced() {
assert_eq!(
IPV6IPV4.view_l().ceil(Ipv6Addr::UNSPECIFIED),
Extended::NegInf
);
assert_eq!(
IPV6IPV4.view_r().floor(Ipv6Addr::UNSPECIFIED),
Extended::NegInf
);
let max = Ipv6Addr::from_bits(u128::MAX);
assert_eq!(IPV6IPV4.view_l().ceil(max), Extended::PosInf);
assert_eq!(IPV6IPV4.view_r().floor(max), Extended::PosInf);
}
#[test]
fn ipv6ipv4_synthetic_inner() {
assert_eq!(
IPV6IPV4.view_l().upper(Extended::NegInf),
Ipv6Addr::UNSPECIFIED
);
assert_eq!(
IPV6IPV4.view_l().upper(Extended::PosInf),
Ipv6Addr::from_bits(u128::MAX)
);
}
crate::law_battery! {
mod ipv6ipv4_laws,
conn: IPV6IPV4,
fine: arb_ipv6(),
coarse: arb_extended_ipv4(),
}
proptest! {
#[test]
fn ipv6ipv4_v4_round_trip(v4 in arb_ipv4()) {
let v6 = IPV6IPV4.view_l().upper(Extended::Finite(v4));
prop_assert_eq!(IPV6IPV4.view_l().ceil(v6), Extended::Finite(v4));
prop_assert_eq!(IPV6IPV4.view_r().floor(v6), Extended::Finite(v4));
}
#[test]
fn ipv6ipv4_floor_le_ceil(a in arb_ipv6()) {
prop_assert!(conn_laws::floor_le_ceil(&IPV6IPV4, a));
}
#[test]
fn ipvxipv4_galois_l(a in arb_ip_addr(), b in arb_extended_ipv4()) {
prop_assert!(conn_laws::galois_l(&IPVXIPV4, a, b));
}
#[test]
fn ipvxipv4_closure_l(a in arb_ip_addr()) {
prop_assert!(conn_laws::closure_l(&IPVXIPV4, a));
}
#[test]
fn ipvxipv4_kernel_l(b in arb_extended_ipv4()) {
prop_assert!(conn_laws::kernel_l(&IPVXIPV4, b));
}
#[test]
fn ipvxipv4_idempotent(a in arb_ip_addr()) {
prop_assert!(conn_laws::idempotent(&IPVXIPV4, a));
}
#[test]
fn ipvxipv6_galois_r(a in arb_ip_addr(), b in arb_extended_ipv6()) {
prop_assert!(conn_laws::galois_r(&IPVXIPV6, a, b));
}
#[test]
fn ipvxipv6_closure_r(a in arb_ip_addr()) {
prop_assert!(conn_laws::closure_r(&IPVXIPV6, a));
}
#[test]
fn ipvxipv6_kernel_r(b in arb_extended_ipv6()) {
prop_assert!(conn_laws::kernel_r(&IPVXIPV6, b));
}
}
}