manycast/
custom_module.rs

1use std::fmt::Display;
2use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
3
4use manycastr::{address::Value::V4, address::Value::V6, Address, IPv6};
5
6pub mod manycastr {
7    tonic::include_proto!("manycastr");
8}
9
10impl Display for Address {
11    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12        let str = match &self.value {
13            Some(V4(v4)) => Ipv4Addr::from(*v4).to_string(),
14            Some(V6(v6)) => Ipv6Addr::new(
15                (v6.p1 >> 48) as u16,
16                (v6.p1 >> 32) as u16,
17                (v6.p1 >> 16) as u16,
18                v6.p1 as u16,
19                (v6.p2 >> 48) as u16,
20                (v6.p2 >> 32) as u16,
21                (v6.p2 >> 16) as u16,
22                v6.p2 as u16,
23            )
24            .to_string(),
25            None => String::from("None"),
26        };
27        write!(f, "{str}")
28    }
29}
30
31impl Address {
32    pub fn is_v6(&self) -> bool {
33        matches!(&self.value, Some(V6(_)))
34    }
35
36    /// Get the prefix of the address
37    ///
38    /// /24 for IPv4 and /48 for IPv6
39    ///
40    #[allow(dead_code)]
41    pub fn get_prefix(&self) -> u64 {
42        match &self.value {
43            Some(V4(v4)) => {
44                // Return the sum of first 24 bits
45                ((v4 >> 8) & 0x00FFFFFF).into()
46            }
47            Some(V6(v6)) => {
48                // Return the sum of first 48 bits
49                (v6.p1 >> 16) & 0x0000FFFFFFFF
50            }
51            None => 0,
52        }
53    }
54
55    /// Get the IPv4 address as u32
56    ///
57    /// Panic if the address is not IPv4
58    pub fn get_v4(&self) -> u32 {
59        match &self.value {
60            Some(V4(v4)) => *v4,
61            _ => panic!("Not a v4 address"),
62        }
63    }
64
65    /// Get the IPv6 address as u128
66    ///
67    /// Panic if the address is not IPv6
68    pub fn get_v6(&self) -> u128 {
69        match &self.value {
70            Some(V6(v6)) => (v6.p1 as u128) << 64 | v6.p2 as u128,
71            _ => panic!("Not a v6 address"),
72        }
73    }
74}
75
76// convert bytes into Address
77impl From<&[u8]> for Address {
78    fn from(bytes: &[u8]) -> Self {
79        match bytes.len() {
80            4 => {
81                let mut ip = [0; 4];
82                ip.copy_from_slice(bytes);
83                Address {
84                    value: Some(V4(u32::from_be_bytes(ip))),
85                }
86            }
87            16 => {
88                let mut ip = [0; 16];
89                ip.copy_from_slice(bytes);
90                Address {
91                    value: Some(V6(IPv6 {
92                        p1: u64::from_be_bytes(ip[0..8].try_into().unwrap()),
93                        p2: u64::from_be_bytes(ip[8..16].try_into().unwrap()),
94                    })),
95                }
96            }
97            _ => panic!("Invalid IP address length"),
98        }
99    }
100}
101
102impl From<[u8; 4]> for Address {
103    fn from(bytes: [u8; 4]) -> Self {
104        Address {
105            value: Some(V4(u32::from_be_bytes(bytes))),
106        }
107    }
108}
109
110impl From<u32> for Address {
111    fn from(bytes: u32) -> Self {
112        Address {
113            value: Some(V4(bytes)),
114        }
115    }
116}
117
118impl From<u128> for Address {
119    fn from(bytes: u128) -> Self {
120        Address {
121            value: Some(V6(IPv6 {
122                p1: (bytes >> 64) as u64,
123                p2: (bytes & 0xFFFFFFFFFFFFFFFF) as u64,
124            })),
125        }
126    }
127}
128
129impl From<[u8; 16]> for Address {
130    fn from(bytes: [u8; 16]) -> Self {
131        Address {
132            value: Some(V6(IPv6 {
133                p1: u64::from_be_bytes(bytes[0..8].try_into().unwrap()),
134                p2: u64::from_be_bytes(bytes[8..16].try_into().unwrap()),
135            })),
136        }
137    }
138}
139
140// Convert String into an Address
141impl From<String> for Address {
142    fn from(s: String) -> Self {
143        if let Ok(ip) = s.parse::<IpAddr>() {
144            // handle standard IP string format (e.g., 2001::1, 1.1.1.1)
145            match ip {
146                IpAddr::V4(v4_addr) => Address {
147                    value: Some(V4(u32::from_be_bytes(v4_addr.octets()))),
148                },
149                IpAddr::V6(v6_addr) => Address {
150                    value: Some(V6(IPv6 {
151                        p1: u64::from_be_bytes(v6_addr.octets()[0..8].try_into().unwrap()),
152                        p2: u64::from_be_bytes(v6_addr.octets()[8..16].try_into().unwrap()),
153                    })),
154                },
155            }
156        } else if let Ok(ip_number) = s.parse::<u128>() {
157            // attempt to interpret as a raw IP number
158            if ip_number <= u32::MAX as u128 {
159                // IPv4
160                Address {
161                    value: Some(V4(ip_number as u32)),
162                }
163            } else {
164                // IPv6
165                Address {
166                    value: Some(V6(IPv6 {
167                        p1: (ip_number >> 64) as u64,                // Most significant 64 bits
168                        p2: (ip_number & 0xFFFFFFFFFFFFFFFF) as u64, // Least significant 64 bits
169                    })),
170                }
171            }
172        } else {
173            panic!("Invalid IP address or IP number");
174        }
175    }
176}
177
178impl From<&String> for Address {
179    fn from(s: &String) -> Self {
180        Address::from(s.to_string())
181    }
182}
183
184impl From<&str> for Address {
185    fn from(s: &str) -> Self {
186        Address::from(s.to_string())
187    }
188}
189
190impl From<IpAddr> for Address {
191    fn from(ip: IpAddr) -> Self {
192        match ip {
193            IpAddr::V4(v4_addr) => Address {
194                value: Some(V4(u32::from_be_bytes(v4_addr.octets()))),
195            },
196            IpAddr::V6(v6_addr) => Address {
197                value: Some(V6(IPv6 {
198                    p1: u64::from_be_bytes(v6_addr.octets()[0..8].try_into().unwrap()),
199                    p2: u64::from_be_bytes(v6_addr.octets()[8..16].try_into().unwrap()),
200                })),
201            },
202        }
203    }
204}
205
206pub trait Separated {
207    fn with_separator(&self) -> String;
208}
209
210fn format_number(number: usize) -> String {
211    let number_str = number.to_string();
212    let chunks: Vec<&str> = number_str
213        .as_bytes()
214        .rchunks(3)
215        .rev()
216        .map(std::str::from_utf8)
217        .collect::<Result<Vec<&str>, _>>()
218        .expect("Unable to format number");
219
220    chunks.join(",")
221}
222
223impl Separated for u32 {
224    fn with_separator(&self) -> String {
225        format_number(*self as usize)
226    }
227}
228
229impl Separated for usize {
230    fn with_separator(&self) -> String {
231        format_number(*self)
232    }
233}