#![no_std]
use core::{
array,
net::{IpAddr, Ipv4Addr, Ipv6Addr},
ops::Add,
};
pub struct Ipsum<T>(pub T);
impl Add for Ipsum<Ipv4Addr> {
type Output = Ipv4Addr;
fn add(self, rhs: Self) -> Self::Output {
let inner = self.0;
let rhs = rhs.0;
let mut it = inner
.octets()
.into_iter()
.zip(rhs.octets().into_iter())
.map(|(o1, o2)| o1.saturating_add(o2));
let res: [u8; 4] = array::from_fn(|_| it.next().unwrap());
res.into()
}
}
impl Add for Ipsum<Ipv6Addr> {
type Output = Ipv6Addr;
fn add(self, rhs: Self) -> Self::Output {
let inner = self.0;
let rhs = rhs.0;
let mut it = inner
.octets()
.into_iter()
.zip(rhs.octets().into_iter())
.map(|(o1, o2)| o1.saturating_add(o2));
let res: [u8; 16] = array::from_fn(|_| it.next().unwrap());
res.into()
}
}
impl Add for Ipsum<IpAddr> {
type Output = IpAddr;
fn add(self, rhs: Self) -> Self::Output {
match (self.0, rhs.0) {
(IpAddr::V4(lhs), IpAddr::V4(rhs)) => IpAddr::V4(Ipsum(lhs) + Ipsum(rhs)),
(IpAddr::V4(lhs), IpAddr::V6(rhs)) => {
IpAddr::V4(Ipsum(lhs) + Ipsum(rhs.to_ipv4().unwrap()))
}
(IpAddr::V6(lhs), IpAddr::V4(rhs)) => {
IpAddr::V4(Ipsum(lhs.to_ipv4().unwrap()) + Ipsum(rhs))
}
(IpAddr::V6(lhs), IpAddr::V6(rhs)) => IpAddr::V6(Ipsum(lhs) + Ipsum(rhs)),
}
}
}
#[cfg(test)]
mod tests {
use core::u16;
use super::*;
#[test]
fn v4() {
let result = Ipsum(Ipv4Addr::new(1, 2, 3, 4)) + Ipsum(Ipv4Addr::new(1, 2, 3, 255));
assert_eq!(result, Ipv4Addr::new(2, 4, 6, 255));
}
#[test]
fn v6() {
let result = Ipsum(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0))
+ Ipsum(Ipv6Addr::new(0x2001, 0xdb8, 1, 2, 3, 4, 5, u16::MAX));
let parts1 = 0x2001u16.to_be_bytes();
let parts2 = 0xdb8u16.to_be_bytes();
assert_eq!(
result,
Ipv6Addr::new(
u16::from_be_bytes([parts1[0].saturating_mul(2), parts1[1].saturating_mul(2)]),
u16::from_be_bytes([parts2[0].saturating_mul(2), parts2[1].saturating_mul(2)]),
1,
2,
3,
4,
5,
u16::MAX
)
);
}
#[test]
fn mixed() {
let result = Ipsum(IpAddr::from([127, 0, 0, 1]))
+ Ipsum(Ipv4Addr::new(192, 168, 2, 4).to_ipv6_mapped().into());
assert_eq!(result, Ipv4Addr::new(127u8.saturating_add(192), 168, 2, 5));
}
#[test]
#[should_panic]
fn panics() {
let _kbye = Ipsum(IpAddr::from([127, 0, 0, 1]))
+ Ipsum(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).into());
}
}