use std::fmt;
#[cfg(test)]
use quickcheck::{Arbitrary, Gen};
use crate::types::Bitfield;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Features(Bitfield);
assert_send_and_sync!(Features);
impl fmt::Debug for Features {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut need_comma = false;
if self.supports_seipdv1() {
f.write_str("SEIPDv1")?;
need_comma = true;
}
if self.supports_seipdv2() {
if need_comma { f.write_str(", ")?; }
f.write_str("SEIPDv2")?;
need_comma = true;
}
for i in self.0.iter_set() {
match i {
FEATURE_FLAG_SEIPDV1 => (),
FEATURE_FLAG_SEIPDV2 => (),
i => {
if need_comma { f.write_str(", ")?; }
write!(f, "#{}", i)?;
need_comma = true;
}
}
}
if let Some(padding) = self.0.padding_bytes() {
if need_comma { f.write_str(", ")?; }
write!(f, "+padding({} bytes)", padding)?;
}
Ok(())
}
}
impl Features {
pub fn new<B>(bytes: B) -> Self
where B: AsRef<[u8]>
{
Features(bytes.as_ref().to_vec().into())
}
pub fn empty() -> Self {
Self::new(&[][..])
}
pub fn sequoia() -> Self {
let v : [u8; 1] = [ 0 ];
Self::new(&v[..])
.set_seipdv1()
.set_seipdv2()
}
pub fn as_bitfield(&self) -> &Bitfield {
&self.0
}
pub fn as_bitfield_mut(&mut self) -> &mut Bitfield {
&mut self.0
}
pub fn normalized_eq(&self, other: &Self) -> bool {
self.0.normalized_eq(&other.0)
}
pub fn get(&self, bit: usize) -> bool {
self.0.get(bit)
}
pub fn set(mut self, bit: usize) -> Self {
self.0.set(bit);
self.0.canonicalize();
self
}
pub fn clear(mut self, bit: usize) -> Self {
self.0.clear(bit);
self.0.canonicalize();
self
}
pub fn supports_seipdv1(&self) -> bool {
self.get(FEATURE_FLAG_SEIPDV1)
}
pub fn set_seipdv1(self) -> Self {
self.set(FEATURE_FLAG_SEIPDV1)
}
pub fn clear_seipdv1(self) -> Self {
self.clear(FEATURE_FLAG_SEIPDV1)
}
pub fn supports_seipdv2(&self) -> bool {
self.get(FEATURE_FLAG_SEIPDV2)
}
pub fn set_seipdv2(self) -> Self {
self.set(FEATURE_FLAG_SEIPDV2)
}
pub fn clear_seipdv2(self) -> Self {
self.clear(FEATURE_FLAG_SEIPDV2)
}
}
const FEATURE_FLAG_SEIPDV1: usize = 0;
const FEATURE_FLAG_SEIPDV2: usize = 3;
#[cfg(test)]
impl Arbitrary for Features {
fn arbitrary(g: &mut Gen) -> Self {
Self::new(Vec::arbitrary(g))
}
}
#[cfg(test)]
mod tests {
use super::*;
quickcheck! {
fn roundtrip(val: Features) -> bool {
let mut q_bytes = val.as_bitfield().as_bytes().to_vec();
let q = Features::new(&q_bytes);
assert_eq!(val, q);
assert!(val.normalized_eq(&q));
q_bytes.push(0);
let q = Features::new(&q_bytes);
assert!(val != q);
assert!(val.normalized_eq(&q));
q_bytes.push(0);
let q = Features::new(&q_bytes);
assert!(val != q);
assert!(val.normalized_eq(&q));
true
}
}
#[test]
fn set_clear() {
let a = Features::new(&[ 0x5, 0x1, 0x0, 0xff ]);
let b = Features::new(&[])
.set(0).set(2)
.set(8)
.set(24).set(25).set(26).set(27).set(28).set(29).set(30).set(31);
assert_eq!(a, b);
let b = b.clear(0);
assert!(a != b);
assert!(! a.normalized_eq(&b));
let b = b.set(0);
assert_eq!(a, b);
assert!(a.normalized_eq(&b));
let b = b.clear(8);
assert!(a != b);
assert!(! a.normalized_eq(&b));
let b = b.set(8);
assert_eq!(a, b);
assert!(a.normalized_eq(&b));
let b = b.clear(31);
assert!(a != b);
assert!(! a.normalized_eq(&b));
let b = b.set(31);
assert_eq!(a, b);
assert!(a.normalized_eq(&b));
let a = a.set(10);
assert!(a != b);
assert!(! a.normalized_eq(&b));
let b = b.set(10);
assert_eq!(a, b);
assert!(a.normalized_eq(&b));
let a = a.set(32);
assert!(a != b);
assert!(! a.normalized_eq(&b));
let b = b.set(32);
assert_eq!(a, b);
assert!(a.normalized_eq(&b));
let a = a.set(1000);
assert!(a != b);
assert!(! a.normalized_eq(&b));
let b = b.set(1000);
assert_eq!(a, b);
assert!(a.normalized_eq(&b));
}
#[test]
fn known() {
let a = Features::empty().set_seipdv1();
let b = Features::new(&[ 0x1 ]);
assert_eq!(a, b);
assert!(a.normalized_eq(&b));
let a = Features::empty().set_seipdv2();
let b = Features::new(&[ 0x8 ]);
assert_eq!(a, b);
assert!(a.normalized_eq(&b));
#[allow(deprecated)]
let a = Features::empty().set_seipdv1().set_seipdv2();
let b = Features::new(&[ 0x1 | 0x8 ]);
assert_eq!(a, b);
assert!(a.normalized_eq(&b));
}
}