1use std::fmt::{Debug, Display, Formatter};
2use std::hash::{Hash, Hasher};
3use std::net::Ipv6Addr;
4use std::str::FromStr;
5use bytemuck::{Pod, Zeroable};
6use crate::integers::NetworkOrderU16;
7
8#[derive(Copy, Clone, Pod, Zeroable, Ord, PartialOrd, Eq, PartialEq)]
9#[repr(C, packed)]
10pub struct IpAddr {
11 octets: [u8; 16]
12}
13
14impl IpAddr {
15 pub const fn to_std(self) -> std::net::IpAddr {
16 Ipv6Addr::from_bits(u128::from_be_bytes(self.octets)).to_canonical()
17 }
18
19 pub const fn from_std(ip: std::net::IpAddr) -> Self {
20 let v6 = match ip {
21 std::net::IpAddr::V4(v4) => v4.to_ipv6_mapped(),
22 std::net::IpAddr::V6(v6) => v6,
23 };
24
25 Self { octets: v6.octets() }
26 }
27}
28
29
30#[derive(Copy, Clone, Pod, Zeroable, Ord, PartialOrd, Eq, PartialEq)]
31#[repr(C, packed)]
32pub struct SocketAddr {
33 ip: IpAddr,
34 port: NetworkOrderU16
35}
36
37impl SocketAddr {
38 pub const fn to_std(self) -> std::net::SocketAddr {
39 std::net::SocketAddr::new(
40 self.ip.to_std(),
41 self.port.get()
42 )
43 }
44
45 pub const fn from_std(sock: std::net::SocketAddr) -> Self {
46 Self {
47 ip: IpAddr::from_std(sock.ip()),
48 port: NetworkOrderU16::new(sock.port())
49 }
50 }
51
52 pub const fn ip(&self) -> IpAddr {
53 self.ip
54 }
55
56 pub const fn port(&self) -> u16 {
57 self.port.get()
58 }
59}
60
61macro_rules! impl_display_debug {
62 ($($type:ty),+) => {$(
63 impl Display for $type {
64 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
65 Display::fmt(&self.to_std(), f)
66 }
67 }
68
69 impl Debug for $type {
70 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
71 Debug::fmt(&self.to_std(), f)
72 }
73 }
74 )+};
75}
76
77impl_display_debug!(IpAddr, SocketAddr);
78
79macro_rules! impl_byte_hash {
80 ($($type:ty),+) => {$(
81 impl Hash for $type {
82 fn hash<H: Hasher>(&self, state: &mut H) {
83 state.write(bytemuck::bytes_of(self))
84 }
85
86 fn hash_slice<H: Hasher>(data: &[Self], state: &mut H)
87 where
88 Self: Sized,
89 {
90 state.write(bytemuck::cast_slice(data))
91 }
92 }
93 )+};
94}
95
96impl_byte_hash!(IpAddr, SocketAddr);
97
98macro_rules! impl_from_str {
99 ($($ty:ident),+) => {$(
100 impl FromStr for $ty {
101 type Err = <std::net::$ty as FromStr>::Err;
102
103 fn from_str(s: &str) -> Result<Self, Self::Err> {
104 s.parse().map(Self::from_std)
105 }
106 }
107 )*};
108}
109
110impl_from_str!(IpAddr, SocketAddr);