network/fundamentals/ip/
ipv4.rs1use core::fmt::Display;
2
3use crate::Ipv6;
4
5#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
6#[repr(transparent)]
7pub struct Ipv4([u8; 4]);
8
9impl Ipv4 {
10 pub const LOCALHOST: Self = Self([127, 0, 0, 1]);
11 pub const BROADCAST: Self = Self([255, 255, 255, 255]);
12
13 pub const fn new(value: [u8; 4]) -> Self {
14 Self(value)
15 }
16
17 pub const fn into_inner(self) -> [u8; 4] {
18 self.0
19 }
20
21 pub const fn from_inner(value: [u8; 4]) -> Self {
22 Self(value)
23 }
24
25 pub const fn is_multicast(&self) -> bool {
26 self.0[0] >= 224 && self.0[0] <= 239
27 }
28
29 pub const fn is_broadcast(&self) -> bool {
30 u32::from_be_bytes(self.0) == u32::from_be_bytes(Self::BROADCAST.0)
31 }
32
33 pub const fn to_ipv6_mapped(&self) -> Ipv6 {
34 Ipv6::new([
35 0,
36 0,
37 0,
38 0,
39 0,
40 0xFFFF,
41 u16::from_be_bytes([self.0[0], self.0[1]]),
42 u16::from_be_bytes([self.0[2], self.0[3]]),
43 ])
44 }
45
46 pub const fn into_smoltcp(self) -> core::net::Ipv4Addr {
47 core::net::Ipv4Addr::new(self.0[0], self.0[1], self.0[2], self.0[3])
48 }
49
50 pub const fn from_smoltcp(value: &core::net::Ipv4Addr) -> Self {
51 Self(value.octets())
52 }
53}
54
55impl TryFrom<&str> for Ipv4 {
56 type Error = ();
57
58 fn try_from(value: &str) -> Result<Self, Self::Error> {
59 let mut result = [0; 4];
60 let mut index = 0;
61
62 for part in value.split('.') {
63 if index >= 4 {
64 return Err(());
65 }
66 let part = part.parse::<u8>().map_err(|_| ())?;
67 result[index] = part;
68 index += 1;
69 }
70 if index != 4 {
71 return Err(());
72 }
73
74 Ok(Self::new(result))
75 }
76}
77
78impl Display for Ipv4 {
79 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80 write!(f, "{}.{}.{}.{}", self.0[0], self.0[1], self.0[2], self.0[3])
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use alloc::string::ToString;
87
88 use super::*;
89
90 #[test]
91 fn test_ipv4_display() {
92 let ip = Ipv4::new([192, 168, 1, 1]);
93
94 assert_eq!(ip.to_string(), "192.168.1.1");
95 }
96
97 #[test]
98 fn test_ipv4_try_from() {
99 let ip = Ipv4::try_from("0.0.0.0").unwrap();
100
101 assert_eq!(ip.0, [0, 0, 0, 0]);
102
103 Ipv4::try_from("1.2b.3.4").unwrap_err();
104
105 Ipv4::try_from("1.2.3.4.5").unwrap_err();
106
107 Ipv4::try_from("1.2.3").unwrap_err();
108
109 let ip = Ipv4::try_from("4.3.2.1").unwrap();
110
111 assert_eq!(ip.0, [4, 3, 2, 1]);
112 }
113}