use regex::Regex;
use std::{u8, u16};
enum IpAddrVersion {
V4 {mask: u8, addr:[u8; 4]},
V6 {mask: u8, addr:[u16; 8]},
}
type IP = IpAddrVersion;
impl IpAddrVersion {
fn is_valid_v6(&self) -> bool {
match self {
Self::V4{..} => false,
Self::V6{..} => true,
}
}
// TODO
fn regex_match_v6() -> bool {false}
fn to_string(&self) -> String {
match self {
Self::V4{mask, addr} => {
format!("{}.{}.{}.{}/{}", addr[0], addr[1], addr[2], addr[3], mask)
},
Self::V6{mask, addr} => {
let mut ipv6 = String::new();
for block in addr {
ipv6.push_str(&format!("{:x}", block));
ipv6.push_str(":");
}
ipv6.pop();
ipv6.push_str("/");
ipv6.push_str(&mask.to_string());
return ipv6
},
}
}
fn to_string_compressed(&self) -> String {
match self {
Self::V4{mask, addr} => Self::to_string(&Self),
Self::V6{mask, addr} => {
let mut ipv6 = String::new();
let mut null_block_pattern: (usize, usize) = (0,0); // (start, length)
let mut null_block_pattern_record = null_block_pattern;
// find the longest consecutive null pattern
for (i, block) in addr.iter().enumerate() {
if block==0 {
if null_block_pattern.0 + null_block_pattern.1 == i{
null_block_pattern.1 +=1;
} else {
if null_block_pattern.1 > null_block_pattern_record.1 {
null_block_pattern_record = null_block_pattern;
}
null_block_pattern.0 = i;
null_block_pattern.1 = 1;
}
}
}
if null_block_pattern.1 > null_block_pattern_record.1 {
null_block_pattern = null_block_pattern_record;
}
for (i, block) in addr.iter().enumerate() {
if i >= null_block_pattern_record.1
&& i <= null_block_pattern_record.0 + null_block_pattern_record.1 {
continue;
} else if i == null_block_pattern_record.0 + null_block_pattern_record.1 {
ipv6.push_str(":");
} else {
ipv6.push_str(&format!("{:x}", block));
ipv6.push_str(":");
}
}
ipv6.pop();
ipv6.push_str("/");
ipv6.push_str(&mask.to_string());
return ipv6
},
}
}
fn from_string(input: &String) -> IpAddrVersion {
let reg_v4 = Regex::new(r"\.").unwrap();
if reg_v4.is_match(input) {
//println!("Found IPV4 input string!"); // DEBUG
let blocks = input.split('.');
let blocks: Vec<&str> = blocks.collect();
let mut v4_arr: [u8; 4] = [0;4];
if blocks.len()==4 {
for (i, val) in blocks.iter().enumerate() {
let block_u8 = u8::from_str_radix(val, 10);
match block_u8 {
Ok(v) => v4_arr = v,
Err(_) => panic!("Could not interpret {val} as an decimal number!"),
}
}
}
return IpAddrVersion::V4{mask: 0, addr: v4_arr}
}
let blocks = input.split(':');
let blocks: Vec<&str> = blocks.collect();
let mut v6_arr: [u16; 8] = [0;8];
if blocks.len()==8 {
for (i,val) in blocks.iter().enumerate() {
let block_u16 = u16::from_str_radix(val, 16);
match block_u16 {
Ok(v) => v6_arr = v,
Err(_) => panic!("Could not interpret {val} as an hexadecimal number!"),
}
}
}
return IpAddrVersion::V6{mask: 0, addr: v6_arr}
}
}
fn main() {
//let localhost = IpAddrVersion::V4(127, 0, 0, 1);
let localhost_v6 = IP::from_string(&String::from("2001:0:0:0:0:dc00:0:6"));
let localhost_v4 = IP::from_string(&String::from("127.0.0.1"));
println!("{}", localhost_v4.to_string());
println!("{}", localhost_v6.to_string());
//print_ip_addr(&String::from("localhost"), &localhost_v6);
//print_ip_addr(&String::from("localhost"), &localhost_v4); // verify localhost is still in scope!
}
fn print_ip_addr(host_name: &String, ip_addr: &IpAddrVersion) {
println!("Host: {} IP: {}", host_name, match ip_addr {
IP::V6{mask: m, addr: arr} => format!("{:?}/{}", arr, m),
IP::V4{mask: m, addr: [a,b,c,d]} => format!("{}.{}.{}.{}/{}",
a.to_string(), b.to_string(), c.to_string(), d.to_string(), m )
}
);
}