use std::str::FromStr; use super::NetworkingErr; #[derive(Debug, PartialEq, Eq)] pub struct InvalidIPErr; /// Ip address enum that includes associated type /// /// # Example /// ``` /// //Loopback Addresses: /// IpAddr::V4(127, 0, 0, 1) /// IpAddr::V6(String::from("::1")) /// ``` #[allow(unused)] #[derive(Debug, PartialEq, Eq, Clone)] pub enum IpAddr { V4(u8, u8, u8, u8), V6(String) } impl IpAddr { /// Function that generates ar array of 4 octets / error /// from an IpAddr /// /// # Limitation /// Currently only works for IPs of type IPv4 /// # Example /// ``` /// let ip: IpAddr = IpAddr::V4(127, 0, 0, 1); /// /// let ip_add: [u8; 4] = ip.to_arr(); /// >>> ip_add = [127, 0, 0, 1] /// ``` pub fn to_arr(&self) -> Result<[u8; 4], NetworkingErr> { match self { IpAddr::V4(o1, o2, o3, o4) => { Ok([*o1, *o2, *o3, *o4]) } _ => Err(NetworkingErr::InvalidIPErr) } } /// Function that generates a IpAddr / Err from an array of /// a octests /// /// # Limitation /// Currently only works for IPs of type IPv4 /// # Example /// ``` /// let ip_add: [u8; 4] = [127, 0, 0, 1]; /// /// let ip: IpAddr = IpAddr::V4(127, 0, 0, 1); /// >>> ip_add = [127, 0, 0, 1] /// ``` pub fn from_arr(arr: &[u8; 4]) -> Result { Ok(IpAddr::V4(arr[0], arr[1], arr[2], arr[3])) } } /// Function that converts an Unsigned 32-bit Ip address /// into an IpAddr /// /// # Limitation /// Currently only works for IPs of type IPv4 /// # Example /// ``` /// let ip: u32 = 2_130_706_433; /// /// let ip_u32: u32 = u32::from(ip); /// ip_u32 = 2130706433; /// ``` impl From for u32 { fn from(ip: IpAddr) -> Self { u32::from_be_bytes(ip.to_arr().unwrap()) } } impl ToString for IpAddr { /// Function that returns an IP address in string form fn to_string(&self) -> String { match self { IpAddr::V4(oct1, oct2, oct3, oct4) => format!("{}.{}.{}.{}", oct1, oct2, oct3, oct4), IpAddr::V6(addr) => format!("{}", addr) } } } impl FromStr for IpAddr { type Err = NetworkingErr; /// Function that generates a IpAddr / Err from a string /// /// # Limitation /// Currently only works for IPs of type IPv4 /// # Example /// ``` /// let ip: &str = "127.0.0.1"; /// /// let parsed_ip: IpAddr = IpAddr::from_str(ip); /// ///parsed_ip = IpAddr::V4(127,0,0,1) /// ``` fn from_str(s: &str) -> Result { let split_ip = s.split('.'); if split_ip.clone().count() != 4 { //Invalid IP address entered return Err(super::NetworkingErr::InvalidIPErr) } let mut ip: [u8; 4] = Default::default(); //Go through each octet and ensure it can be parsed; for (i, oct) in split_ip.into_iter().enumerate() { if i > ip.len() { //Ip string is out of the range of the 4 octets in an IPv4 Address return Err(NetworkingErr::InvalidIPErr) } match oct.parse::() { Ok(parsed_oct) => ip[i] = parsed_oct, Err(_) => return Err(NetworkingErr::InvalidIPErr) } } Ok(IpAddr::from_arr(&ip)?) } } /// Function that takes in an IP address and then prints a formatted string to the CLI /// /// # Example /// ``` /// let ip = IpAddr::V4(127, 0, 0, 1); /// /// print_ip(ip); /// //Output: IP Address: 127.0.0.1 /// ``` #[allow(unused)] pub fn print_ip(ip_address: IpAddr) { println!("IP Address: {}", ip_address.to_string()) } mod tests { #[test] /// Tests if an IP is converted to a string /// correctly using the ToString trait fn ip_to_string() { use super::*; let ip = IpAddr::V4(192, 168, 0, 1); assert_eq!(ip.to_string(), "192.168.0.1") } #[test] /// Tests if an IP is converted from a string /// correctly using the FromString trait fn string_to_ip() { use super::*; let ip = "127.0.0.1"; assert_eq!(IpAddr::from_str(ip).unwrap(), IpAddr::V4(127, 0, 0, 1)) } #[test] #[should_panic] ///Tests if an invalid Ip will cause a panic when /// converting from a string to an IpAddr fn invalid_string_to_ip() { use super::*; let ip = "127.0.0.0.1"; IpAddr::from_str(ip).unwrap(); assert_eq!(IpAddr::from_str(ip), Err(NetworkingErr::InvalidIPErr)) } #[test] /// Tests the conversion of an IPv4 Address to /// an array fn ipaddr_to_arr() { use super::*; let mut ip_addr = IpAddr::V4(127, 0, 0, 1); assert_eq!(ip_addr.to_arr().unwrap(), [127, 0, 0, 1]); ip_addr = IpAddr::V6("::".to_string()); assert_eq!(ip_addr.to_arr().unwrap_err(), NetworkingErr::InvalidIPErr); } #[test] /// Tests the conversion of an array to // an IPv4 Address fn arr_to_ipaddr() { use super::*; let ip_addr: [u8; 4] = [127, 0, 0, 1]; assert_eq!(IpAddr::from_arr(&ip_addr).unwrap(), IpAddr::V4(127, 0, 0, 1)); } #[test] /// Tests the conversion of an IPv4 Address to /// an unsigned 32-bit integer fn ipaddr_to_u32() { use super::*; let ip = IpAddr::V4(0, 0, 0, 0); assert_eq!(0, u32::from(ip)); let ip = IpAddr::V4(127, 0, 0, 1); assert_eq!(2_130_706_433, u32::from(ip)); let ip = IpAddr::V4(10, 10, 10, 0); assert_eq!(168_430_080, u32::from(ip)); let ip = IpAddr::V4(255, 255, 255, 255); assert_eq!(u32::MAX, u32::from(ip)); } }