use super::xorable::Xorable;
use std::cmp::{self, Ordering};
use std::fmt::Result as FmtResult;
use std::fmt::{Binary, Debug, Formatter};
use std::hash::{Hash, Hasher};
#[cfg(test)]
use std::str::FromStr;
#[derive(
Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize,
)]
pub struct VersionedPrefix<T: Clone + Copy + Default + Binary + Xorable> {
prefix: Prefix<T>,
version: u64,
}
impl<T: Clone + Copy + Default + Binary + Xorable> VersionedPrefix<T> {
pub fn prefix(&self) -> &Prefix<T> {
&self.prefix
}
pub fn version(&self) -> u64 {
self.version
}
}
impl<T: Clone + Copy + Default + Binary + Xorable> Into<(Prefix<T>, u64)> for VersionedPrefix<T> {
fn into(self) -> (Prefix<T>, u64) {
(self.prefix, self.version)
}
}
#[derive(Clone, Copy, Default, Eq, Deserialize, Serialize)]
pub struct Prefix<T: Clone + Copy + Default + Binary + Xorable> {
bit_count: u16,
name: T,
}
impl<T: Clone + Copy + Default + Binary + Xorable> Prefix<T> {
pub fn new(bit_count: usize, name: T) -> Prefix<T> {
Prefix {
bit_count: cmp::min(bit_count, T::bit_len()) as u16,
name: name.set_remaining(bit_count, false),
}
}
pub fn with_version(self, version: u64) -> VersionedPrefix<T> {
VersionedPrefix {
prefix: self,
version,
}
}
pub fn pushed(mut self, bit: bool) -> Prefix<T> {
self.name = self.name.with_bit(self.bit_count(), bit);
self.bit_count = cmp::min(self.bit_count + 1, T::bit_len() as u16);
self
}
pub fn popped(mut self) -> Prefix<T> {
if self.bit_count > 0 {
self.bit_count -= 1;
self.name = self.name.with_bit(self.bit_count(), false);
}
self
}
pub fn bit_count(&self) -> usize {
self.bit_count as usize
}
pub fn is_compatible(&self, other: &Prefix<T>) -> bool {
let i = self.name.common_prefix(&other.name);
i >= self.bit_count() || i >= other.bit_count()
}
pub fn is_extension_of(&self, other: &Prefix<T>) -> bool {
let i = self.name.common_prefix(&other.name);
i >= other.bit_count() && self.bit_count() > other.bit_count()
}
pub fn is_neighbour(&self, other: &Prefix<T>) -> bool {
let i = self.name.common_prefix(&other.name);
if i >= self.bit_count() || i >= other.bit_count() {
false
} else {
let j = self.name.with_flipped_bit(i).common_prefix(&other.name);
j >= self.bit_count() || j >= other.bit_count()
}
}
pub fn common_prefix(&self, name: &T) -> usize {
cmp::min(self.bit_count(), self.name.common_prefix(name))
}
pub fn matches(&self, name: &T) -> bool {
self.name.common_prefix(name) >= self.bit_count()
}
pub fn cmp_distance(&self, other: &Self, target: &T) -> Ordering {
if self.is_compatible(other) {
Ord::cmp(&self.bit_count, &other.bit_count)
} else {
Ord::cmp(
&other.name.common_prefix(target),
&self.name.common_prefix(target),
)
}
}
pub fn lower_bound(&self) -> T {
self.name.set_remaining(self.bit_count(), false)
}
pub fn upper_bound(&self) -> T {
self.name.set_remaining(self.bit_count(), true)
}
pub fn is_covered_by<'a, U>(&self, prefixes: U) -> bool
where
T: 'a,
U: IntoIterator<Item = &'a Prefix<T>> + Clone,
{
let max_prefix_len = prefixes
.clone()
.into_iter()
.map(|x| x.bit_count())
.max()
.unwrap_or(0);
self.is_covered_by_impl(prefixes, max_prefix_len)
}
fn is_covered_by_impl<'a, U>(&self, prefixes: U, max_prefix_len: usize) -> bool
where
T: 'a,
U: IntoIterator<Item = &'a Prefix<T>> + Clone,
{
prefixes
.clone()
.into_iter()
.any(|x| x.is_compatible(self) && x.bit_count() <= self.bit_count())
|| (self.bit_count() <= max_prefix_len
&& self
.pushed(false)
.is_covered_by_impl(prefixes.clone(), max_prefix_len)
&& self
.pushed(true)
.is_covered_by_impl(prefixes, max_prefix_len))
}
pub fn with_flipped_bit(&self, i: usize) -> Prefix<T> {
if i >= self.bit_count() {
*self
} else {
Prefix::new(self.bit_count(), self.name.with_flipped_bit(i))
}
}
pub fn substituted_in(&self, mut name: T) -> T {
for i in 0..self.bit_count() {
name = name.with_bit(i, self.name.bit(i));
}
name
}
pub fn sibling(&self) -> Prefix<T> {
if self.bit_count > 0 {
self.with_flipped_bit((self.bit_count - 1) as usize)
} else {
*self
}
}
}
impl<T: Clone + Copy + Default + Binary + Xorable> PartialEq<Prefix<T>> for Prefix<T> {
fn eq(&self, other: &Self) -> bool {
self.is_compatible(other) && self.bit_count == other.bit_count
}
}
impl<T: Clone + Copy + Default + Binary + Xorable> PartialOrd<Prefix<T>> for Prefix<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T: Clone + Copy + Default + Binary + Xorable> Ord for Prefix<T> {
fn cmp(&self, other: &Self) -> Ordering {
if self == other {
Ordering::Equal
} else if self.is_compatible(other) {
self.bit_count().cmp(&other.bit_count())
} else {
self.name.cmp(&other.name)
}
}
}
impl<T: Clone + Copy + Default + Binary + Xorable> Hash for Prefix<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
for i in 0..self.bit_count() {
self.name.bit(i).hash(state);
}
}
}
impl<T: Clone + Copy + Default + Binary + Xorable> Binary for Prefix<T> {
fn fmt(&self, formatter: &mut Formatter) -> FmtResult {
let mut binary = self.name.binary();
binary.truncate(self.bit_count());
write!(formatter, "{}", binary)
}
}
impl<T: Clone + Copy + Default + Binary + Xorable> Debug for Prefix<T> {
fn fmt(&self, formatter: &mut Formatter) -> FmtResult {
write!(formatter, "Prefix({:b})", self)
}
}
#[cfg(test)]
impl FromStr for Prefix<u8> {
type Err = String;
fn from_str(bits: &str) -> Result<Prefix<u8>, String> {
let mut name = 0u8;
for (i, bit) in bits.chars().enumerate() {
if bit == '1' {
name |= 1 << (7 - i);
} else if bit != '0' {
return Err(format!(
"'{}' not allowed - the string must represent a binary number.",
bit
));
}
}
Ok(Prefix::new(bits.len(), name))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn prefix() {
assert_eq!(
unwrap!(Prefix::from_str("101")).pushed(true),
unwrap!(Prefix::from_str("1011"))
);
assert_eq!(
unwrap!(Prefix::from_str("101")).pushed(false),
unwrap!(Prefix::from_str("1010"))
);
assert_eq!(
unwrap!(Prefix::from_str("1011")).popped(),
unwrap!(Prefix::from_str("101"))
);
assert!(unwrap!(Prefix::from_str("101")).is_compatible(&unwrap!(Prefix::from_str("1010"))));
assert!(unwrap!(Prefix::from_str("1010")).is_compatible(&unwrap!(Prefix::from_str("101"))));
assert!(
!unwrap!(Prefix::from_str("1010")).is_compatible(&unwrap!(Prefix::from_str("1011")))
);
assert!(unwrap!(Prefix::from_str("101")).is_neighbour(&unwrap!(Prefix::from_str("1111"))));
assert!(
!unwrap!(Prefix::from_str("1010")).is_neighbour(&unwrap!(Prefix::from_str("1111")))
);
assert!(
unwrap!(Prefix::from_str("1010")).is_neighbour(&unwrap!(Prefix::from_str("10111")))
);
assert!(
!unwrap!(Prefix::from_str("101")).is_neighbour(&unwrap!(Prefix::from_str("10111")))
);
assert!(unwrap!(Prefix::from_str("101")).matches(&0b1010_1100));
assert!(!unwrap!(Prefix::from_str("1011")).matches(&0b1010_1100));
assert_eq!(unwrap!(Prefix::from_str("0101")).lower_bound(), 0b0101_0000);
assert_eq!(unwrap!(Prefix::from_str("0101")).upper_bound(), 0b0101_1111);
assert_eq!(Prefix::<u64>::new(64, 0).bit_count(), 64);
assert_eq!(Prefix::<u64>::new(65, 0).bit_count(), 64);
}
}