1#![no_std]
2
3use core::{
4 array,
5 net::{IpAddr, Ipv4Addr, Ipv6Addr},
6 ops::Add,
7};
8
9pub struct Ipsum<T>(pub T);
18
19impl Add for Ipsum<Ipv4Addr> {
20 type Output = Ipv4Addr;
21
22 fn add(self, rhs: Self) -> Self::Output {
23 let inner = self.0;
24 let rhs = rhs.0;
25 let mut it = inner
26 .octets()
27 .into_iter()
28 .zip(rhs.octets().into_iter())
29 .map(|(o1, o2)| o1.saturating_add(o2));
30 let res: [u8; 4] = array::from_fn(|_| it.next().unwrap());
31 res.into()
32 }
33}
34
35impl Add for Ipsum<Ipv6Addr> {
36 type Output = Ipv6Addr;
37
38 fn add(self, rhs: Self) -> Self::Output {
39 let inner = self.0;
40 let rhs = rhs.0;
41 let mut it = inner
42 .octets()
43 .into_iter()
44 .zip(rhs.octets().into_iter())
45 .map(|(o1, o2)| o1.saturating_add(o2));
46 let res: [u8; 16] = array::from_fn(|_| it.next().unwrap());
47 res.into()
48 }
49}
50
51impl Add for Ipsum<IpAddr> {
52 type Output = IpAddr;
53
54 fn add(self, rhs: Self) -> Self::Output {
55 match (self.0, rhs.0) {
56 (IpAddr::V4(lhs), IpAddr::V4(rhs)) => IpAddr::V4(Ipsum(lhs) + Ipsum(rhs)),
57 (IpAddr::V4(lhs), IpAddr::V6(rhs)) => {
58 IpAddr::V4(Ipsum(lhs) + Ipsum(rhs.to_ipv4().unwrap()))
59 }
60 (IpAddr::V6(lhs), IpAddr::V4(rhs)) => {
61 IpAddr::V4(Ipsum(lhs.to_ipv4().unwrap()) + Ipsum(rhs))
62 }
63 (IpAddr::V6(lhs), IpAddr::V6(rhs)) => IpAddr::V6(Ipsum(lhs) + Ipsum(rhs)),
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use core::u16;
71
72 use super::*;
73
74 #[test]
75 fn v4() {
76 let result = Ipsum(Ipv4Addr::new(1, 2, 3, 4)) + Ipsum(Ipv4Addr::new(1, 2, 3, 255));
77 assert_eq!(result, Ipv4Addr::new(2, 4, 6, 255));
78 }
79
80 #[test]
81 fn v6() {
82 let result = Ipsum(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0))
83 + Ipsum(Ipv6Addr::new(0x2001, 0xdb8, 1, 2, 3, 4, 5, u16::MAX));
84 let parts1 = 0x2001u16.to_be_bytes();
85 let parts2 = 0xdb8u16.to_be_bytes();
86 assert_eq!(
87 result,
88 Ipv6Addr::new(
89 u16::from_be_bytes([parts1[0].saturating_mul(2), parts1[1].saturating_mul(2)]),
90 u16::from_be_bytes([parts2[0].saturating_mul(2), parts2[1].saturating_mul(2)]),
91 1,
92 2,
93 3,
94 4,
95 5,
96 u16::MAX
97 )
98 );
99 }
100
101 #[test]
102 fn mixed() {
103 let result = Ipsum(IpAddr::from([127, 0, 0, 1]))
104 + Ipsum(Ipv4Addr::new(192, 168, 2, 4).to_ipv6_mapped().into());
105
106 assert_eq!(result, Ipv4Addr::new(127u8.saturating_add(192), 168, 2, 5));
107 }
108
109 #[test]
110 #[should_panic]
111 fn panics() {
112 let _kbye = Ipsum(IpAddr::from([127, 0, 0, 1]))
113 + Ipsum(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).into());
114 }
115}