use num::bigint::BigUint;
use num_traits::identities::One;
use num_traits::identities::Zero;
use num_traits::cast::ToPrimitive;
use num_traits::FromPrimitive;
use core::convert::From;
use core::ops::Rem;
use core::ops::Shr;
use core::clone::Clone;
use std::fmt;
use rle;
#[allow(dead_code)]
#[derive(PartialOrd, PartialEq, Eq, Debug, Clone, Copy)]
pub enum IpVersion {
V4,
V6,
}
pub struct IpBits {
pub version: IpVersion,
pub vt_as_compressed_string: fn(&IpBits, &BigUint) -> String,
pub vt_as_uncompressed_string: fn(&IpBits, &BigUint) -> String,
pub bits: usize,
pub part_bits: usize,
pub dns_bits: usize,
pub rev_domain: &'static str,
pub part_mod: BigUint,
pub host_ofs: BigUint, }
lazy_static! {
static ref V4 : IpBits = {
IpBits {
version: IpVersion::V4,
vt_as_compressed_string: ipv4_as_compressed,
vt_as_uncompressed_string: ipv4_as_compressed,
bits: 32,
part_bits: 8,
dns_bits: 8,
rev_domain: "in-addr.arpa",
part_mod: BigUint::from_usize(1 << 8).unwrap(),
host_ofs: BigUint::one(),
}
};
static ref V6 : IpBits = {
return IpBits {
version: IpVersion::V6,
vt_as_compressed_string: ipv6_as_compressed,
vt_as_uncompressed_string: ipv6_as_uncompressed,
bits: 128,
part_bits: 16,
dns_bits: 4,
rev_domain: "ip6.arpa",
part_mod: BigUint::from_usize(1 << 16).unwrap(),
host_ofs: BigUint::zero(),
};
};
}
impl fmt::Debug for IpBits {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "IpBits: {:?}", self.version)
}
}
impl IpBits {
#[allow(unused_variables)]
pub fn parts(&self, bu: &BigUint) -> Vec<u16> {
let mut vec: Vec<u16> = Vec::new();
let mut my = bu.clone();
let part_mod = BigUint::one() << self.part_bits; for i in 0..(self.bits / self.part_bits) {
vec.push(my.clone().rem(&part_mod).to_u16().unwrap());
my = my.shr(self.part_bits);
}
vec.reverse();
return vec;
}
pub fn as_compressed_string(&self, bu: &BigUint) -> String {
return (self.vt_as_compressed_string)(self, bu);
}
#[allow(dead_code)]
pub fn as_uncompressed_string(&self, bu: &BigUint) -> String {
return (self.vt_as_uncompressed_string)(self, bu);
}
pub fn dns_part_format(&self, i: u8) -> String {
match self.version {
IpVersion::V4 => return format!("{}", i),
IpVersion::V6 => return format!("{:01x}", i),
}
}
}
fn ipv4_as_compressed(ip_bits: &IpBits, host_address: &BigUint) -> String {
let mut ret = String::new();
let mut sep = "";
for part in ip_bits.parts(host_address) {
ret.push_str(sep);
ret.push_str(&format!("{}", part));
sep = ".";
}
return ret;
}
fn ipv6_as_compressed(ip_bits: &IpBits, host_address: &BigUint) -> String {
let mut ret = String::new();
let the_colon = String::from(":");
let the_empty = String::from("");
let mut colon = &the_empty;
let mut done = false;
for rle in rle::code(&ip_bits.parts(host_address)) {
for _ in 0..rle.cnt {
if done || !(rle.part == 0 && rle.max) {
ret.push_str(&format!("{}{:x}", colon, rle.part));
colon = &the_colon;
} else if rle.part == 0 && rle.max {
ret.push_str("::");
colon = &the_empty;
done = true;
break;
}
}
}
return ret;
}
fn ipv6_as_uncompressed(ip_bits: &IpBits, host_address: &BigUint) -> String {
let mut ret = String::new();
let mut sep = "";
for part in ip_bits.parts(host_address) {
ret.push_str(sep);
ret.push_str(&format!("{:04x}", part));
sep = ":";
}
return ret;
}
pub fn v4() -> &'static IpBits {
return &V4;
}
pub fn v6() -> &'static IpBits {
return &V6;
}