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_mdc() {
f.write_str("MDC")?;
need_comma = true;
}
if self.supports_aead() {
if need_comma { f.write_str(", ")?; }
f.write_str("AEAD")?;
need_comma = true;
}
for i in self.0.iter() {
match i {
FEATURE_FLAG_MDC => (),
FEATURE_FLAG_AEAD => (),
i => {
if need_comma { f.write_str(", ")?; }
write!(f, "#{}", i)?;
need_comma = true;
}
}
}
let padding = self.0.padding_len();
if padding > 0 {
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_mdc()
}
pub fn normalized_eq(&self, other: &Self) -> bool {
self.0.normalized_eq(&other.0)
}
pub(crate) fn as_slice(&self) -> &[u8] {
self.0.as_slice()
}
pub fn get(&self, bit: usize) -> bool {
self.0.get(bit)
}
pub fn set(self, bit: usize) -> Self {
Self(self.0.set(bit))
}
pub fn clear(self, bit: usize) -> Self {
Self(self.0.clear(bit))
}
pub fn supports_mdc(&self) -> bool {
self.get(FEATURE_FLAG_MDC)
}
pub fn set_mdc(self) -> Self {
self.set(FEATURE_FLAG_MDC)
}
pub fn clear_mdc(self) -> Self {
self.clear(FEATURE_FLAG_MDC)
}
pub fn supports_aead(&self) -> bool {
self.get(FEATURE_FLAG_AEAD)
}
pub fn set_aead(self) -> Self {
self.set(FEATURE_FLAG_AEAD)
}
pub fn clear_aead(self) -> Self {
self.clear(FEATURE_FLAG_AEAD)
}
}
const FEATURE_FLAG_MDC: usize = 0;
const FEATURE_FLAG_AEAD: usize = 1;
#[cfg(test)]
impl Arbitrary for Features {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
Self::new(Vec::arbitrary(g))
}
}
#[cfg(test)]
mod tests {
use super::*;
quickcheck! {
fn roundtrip(val: Features) -> bool {
let mut q = Features::new(val.as_slice());
assert_eq!(val, q);
assert!(val.normalized_eq(&q));
q.0.raw.push(0);
assert!(val != q);
assert!(val.normalized_eq(&q));
q.0.raw.push(0);
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_mdc();
let b = Features::new(&[ 0x1 ]);
assert_eq!(a, b);
assert!(a.normalized_eq(&b));
let a = Features::empty().set_aead();
let b = Features::new(&[ 0x2 ]);
assert_eq!(a, b);
assert!(a.normalized_eq(&b));
let a = Features::empty().set_mdc().set_aead();
let b = Features::new(&[ 0x1 | 0x2 ]);
assert_eq!(a, b);
assert!(a.normalized_eq(&b));
}
}