use core::ops::Deref;
use std::net::Ipv6Addr;
use cidr::Ipv6Cidr;
use num_bigint::BigUint;
use num_traits::Zero;
use crate::Ipv6CidrSize;
#[derive(Debug, Clone)]
pub struct Ipv6CidrCombiner(Vec<Ipv6Cidr>);
impl Default for Ipv6CidrCombiner {
#[inline]
fn default() -> Self {
Ipv6CidrCombiner::new()
}
}
impl Deref for Ipv6CidrCombiner {
type Target = Vec<Ipv6Cidr>;
#[inline]
fn deref(&self) -> &Vec<Ipv6Cidr> {
&self.0
}
}
impl Ipv6CidrCombiner {
#[inline]
pub const fn new() -> Ipv6CidrCombiner {
Ipv6CidrCombiner(Vec::new())
}
#[inline]
pub fn with_capacity(capacity: usize) -> Ipv6CidrCombiner {
Ipv6CidrCombiner(Vec::with_capacity(capacity))
}
#[inline]
pub const unsafe fn from_ipv6_cidr_vec_unchecked(cidr_vec: Vec<Ipv6Cidr>) -> Ipv6CidrCombiner {
Ipv6CidrCombiner(cidr_vec)
}
#[inline]
pub fn into_ipv6_cidr_vec(self) -> Vec<Ipv6Cidr> {
self.0
}
}
impl Ipv6CidrCombiner {
pub fn push(&mut self, mut cidr: Ipv6Cidr) {
if let Err(mut index) = self.0.binary_search(&cidr) {
if self.0.is_empty() {
self.0.push(cidr);
} else {
let pushable = if index == 0 {
true
} else {
let previous_cidr = self.0.get(index - 1).unwrap();
!previous_cidr.contains(&cidr.first_address())
};
if pushable {
loop {
if index == self.0.len() {
break;
}
let next = self.0.get(index).unwrap();
if cidr.contains(&next.first_address()) {
self.0.remove(index);
} else {
break;
}
}
let mut merging = true;
while merging {
merging = false;
if index < self.0.len() {
let next_cidr = self.0.get(index).unwrap();
let next_bits = next_cidr.network_length();
let bits = cidr.network_length();
if bits > 0 && bits == next_bits {
let next_prefix: u128 = next_cidr.first_address().into();
let prefix: u128 = cidr.first_address().into();
let d = next_prefix ^ prefix;
if d == 1 << (128 - bits) as u128 {
cidr = Ipv6Cidr::new(prefix.into(), bits - 1).unwrap();
self.0.remove(index);
merging = true;
}
}
}
if index > 0 {
let index_dec = index - 1;
let previous_cidr = self.0.get_mut(index_dec).unwrap();
let previous_bits = previous_cidr.network_length();
let bits = cidr.network_length();
if bits > 0 && bits == previous_bits {
let previous_prefix: u128 = previous_cidr.first_address().into();
let prefix: u128 = cidr.first_address().into();
let d = prefix ^ previous_prefix;
if d == 1 << (128 - bits) as u128 {
self.0.remove(index_dec);
index = index_dec;
cidr = Ipv6Cidr::new(previous_prefix.into(), previous_bits - 1)
.unwrap();
merging = true;
}
}
}
}
self.0.insert(index, cidr);
}
}
}
}
#[inline]
pub fn contains(&self, ipv6: &Ipv6Addr) -> bool {
for cidr in self.0.iter() {
if cidr.contains(ipv6) {
return true;
}
}
false
}
#[inline]
pub fn size(&self) -> BigUint {
let mut sum = BigUint::zero();
for cidr in self.0.iter() {
sum += cidr.size();
}
sum
}
}