rust-ipcalc/src/ip.rs
2022-11-23 13:54:59 +01:00

94 lines
2.5 KiB
Rust

use std::fmt::{self,Display}; // needed to implement Display for Ip
use std::convert::From; // needed to implement u32::from(&ip)
// Debug needed for {:?} format
// PartialEq and Eq allows comparisons (usefull for unit tests)
#[derive(Debug,PartialEq,Eq)]
pub enum Ip {
V4([u8 ; 4]),
// V6([u16 ; 8]) // not implemented yet...
}
// implement methods on the Ip type
// 'new' and 'from_str' are arbitrary and could be named differently
impl Ip {
pub fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
Ip::V4([a, b, c, d])
}
pub fn from_str(s: &str) -> Option<Self> {
let tbl : Vec<u8> = s.split('.')
.filter_map(|s| s.parse().ok())
.collect();
Some(Ip::V4(tbl.try_into().ok()?))
}
// totaly useless but an example of an object method :)
pub fn is_even(&self) -> bool {
let Ip::V4([_,_,_,n]) = self;
n % 2 == 0
}
}
// allows conversion from ip to u32 with this syntax:
// `let nbr = u32::from(&ip);`
// use the std::convert::From trait
impl From<&Ip> for u32 {
fn from(src: &Ip) -> u32 {
let mut ip : u32 = 0;
let Ip::V4(array) = src;
for (idx, n) in array.iter().enumerate() {
ip += (*n as u32) << (8 * (3 - idx));
}
ip
}
}
// Display is a standard trait used by format! and println! and others
// to display objects...
impl Display for Ip {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Ip::V4(arr) => write!(f, "{}.{}.{}.{}",
arr[0], arr[1], arr[2], arr[3]),
/*
Ip::V6(arr) => write!(f,
"{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
arr[0], arr[1], arr[2], arr[3],
arr[4], arr[5], arr[6], arr[7])
*/
}
}
}
// Some unit tests, run with:
// `$ cargo test`
#[test]
fn test_ip_new() {
let ip = Ip::new(127, 0, 0, 1);
assert_eq!(ip, Ip::V4([127, 0, 0, 1]));
}
#[test]
fn test_ip_from_str() {
let ip1 = Ip::from_str("127.0.0.1");
assert_eq!(ip1, Some(Ip::V4([127, 0, 0, 1])));
let ip2 = Ip::from_str("512.0.0.1");
assert_eq!(ip2, None);
}
#[test]
fn test_ip_is_even() {
assert_eq!(Ip::new(127, 0, 0, 1).is_even(), false);
assert_eq!(Ip::new(192, 168, 0, 2).is_even(), true);
}
#[test]
fn test_u32_from_ip() {
let ip = Ip::new(127, 0, 0, 1);
let nbr = u32::from(&ip);
assert_eq!(nbr, 0x7f000001);
}