diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2020-07-28 14:53:36 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2020-07-28 14:53:36 +0200 |
commit | 6a7074bdf55b48c9e4598e3fff32b360537ea373 (patch) | |
tree | 86bd510b49674a446af25672226e790587c27ed5 | |
parent | 52d3a63f1f0c0ad130f9a8351ef591aed28004ca (diff) |
openpgp: Extract the Bitfield type from struct Features.
-rw-r--r-- | openpgp/src/types/bitfield.rs | 111 | ||||
-rw-r--r-- | openpgp/src/types/features.rs | 93 | ||||
-rw-r--r-- | openpgp/src/types/mod.rs | 2 |
3 files changed, 128 insertions, 78 deletions
diff --git a/openpgp/src/types/bitfield.rs b/openpgp/src/types/bitfield.rs new file mode 100644 index 00000000..54468989 --- /dev/null +++ b/openpgp/src/types/bitfield.rs @@ -0,0 +1,111 @@ +/// A bitfield. +#[derive(Clone, PartialEq, Eq, Hash)] +pub(crate) struct Bitfield { + pub(crate) raw: Vec<u8>, +} + +impl From<Vec<u8>> for Bitfield { + fn from(raw: Vec<u8>) -> Self { + Self { raw } + } +} + +impl Bitfield { + pub fn iter<'a>(&'a self) -> impl Iterator<Item = usize> + 'a { + self.raw.iter() + .flat_map(|b| { + (0..8).into_iter().map(move |i| { + b & (1 << i) != 0 + }) + }) + .enumerate() + .filter_map(|(i, v)| if v { Some(i) } else { None }) + } + + pub fn padding_len(&self) -> usize { + let mut padding = 0; + for i in (0..self.raw.len()).rev() { + if self.raw[i] == 0 { + padding += 1; + } else { + break; + } + } + padding + } + + /// Compares two feature sets for semantic equality. + pub fn normalized_eq(&self, other: &Self) -> bool { + let (small, big) = if self.raw.len() < other.raw.len() { + (self, other) + } else { + (other, self) + }; + + for (s, b) in small.raw.iter().zip(big.raw.iter()) { + if s != b { + return false; + } + } + + for &b in &big.raw[small.raw.len()..] { + if b != 0 { + return false; + } + } + + true + } + + /// Returns a slice containing the raw values. + pub(crate) fn as_slice(&self) -> &[u8] { + &self.raw + } + + /// Returns whether the specified keyserver preferences flag is set. + pub fn get(&self, bit: usize) -> bool { + let byte = bit / 8; + + if byte >= self.raw.len() { + // Unset bits are false. + false + } else { + (self.raw[byte] & (1 << (bit % 8))) != 0 + } + } + + /// Remove any trailing padding. + fn clear_padding(mut self) -> Self { + while self.raw.len() > 0 && self.raw[self.raw.len() - 1] == 0 { + self.raw.truncate(self.raw.len() - 1); + } + + self + } + + /// Sets the specified keyserver preferences flag. + /// + /// This also clears any padding (trailing NUL bytes). + pub fn set(mut self, bit: usize) -> Self { + let byte = bit / 8; + while self.raw.len() <= byte { + self.raw.push(0); + } + self.raw[byte] |= 1 << (bit % 8); + + self.clear_padding() + } + + /// Clears the specified keyserver preferences flag. + /// + /// This also clears any padding (trailing NUL bytes). + pub fn clear(mut self, bit: usize) -> Self { + let byte = bit / 8; + if byte < self.raw.len() { + self.raw[byte] &= !(1 << (bit % 8)); + } + + self.clear_padding() + } +} + diff --git a/openpgp/src/types/features.rs b/openpgp/src/types/features.rs index f1021d2f..84badd48 100644 --- a/openpgp/src/types/features.rs +++ b/openpgp/src/types/features.rs @@ -3,6 +3,8 @@ use std::fmt; #[cfg(any(test, feature = "quickcheck"))] use quickcheck::{Arbitrary, Gen}; +use crate::types::Bitfield; + /// Describes the features supported by an OpenPGP implementation. /// /// The feature flags are defined in [Section 5.2.3.24 of RFC 4880], @@ -52,9 +54,7 @@ use quickcheck::{Arbitrary, Gen}; /// # Ok(()) } /// ``` #[derive(Clone, PartialEq, Eq, Hash)] -pub struct Features { - raw: Vec<u8>, -} +pub struct Features(Bitfield); impl fmt::Debug for Features { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -71,15 +71,7 @@ impl fmt::Debug for Features { } // Now print any unknown features. - for i in self.raw.iter() - .flat_map(|b| { - (0..8).into_iter().map(move |i| { - b & (1 << i) != 0 - }) - }) - .enumerate() - .filter_map(|(i, v)| if v { Some(i) } else { None }) - { + for i in self.0.iter() { match i { FEATURE_FLAG_MDC => (), FEATURE_FLAG_AEAD => (), @@ -92,15 +84,7 @@ impl fmt::Debug for Features { } // Mention any padding, as equality is sensitive to this. - let mut padding = 0; - for i in (0..self.raw.len()).rev() { - if self.raw[i] == 0 { - padding += 1; - } else { - break; - } - } - + let padding = self.0.padding_len(); if padding > 0 { if need_comma { f.write_str(", ")?; } write!(f, "+padding({} bytes)", padding)?; @@ -117,9 +101,7 @@ impl Features { pub fn new<B>(bytes: B) -> Self where B: AsRef<[u8]> { - Features{ - raw: bytes.as_ref().to_vec(), - } + Features(bytes.as_ref().to_vec().into()) } /// Returns an empty feature set. @@ -158,30 +140,12 @@ impl Features { /// # Ok(()) } /// ``` pub fn normalized_eq(&self, other: &Self) -> bool { - let (small, big) = if self.raw.len() < other.raw.len() { - (self, other) - } else { - (other, self) - }; - - for (s, b) in small.raw.iter().zip(big.raw.iter()) { - if s != b { - return false; - } - } - - for &b in &big.raw[small.raw.len()..] { - if b != 0 { - return false; - } - } - - true + self.0.normalized_eq(&other.0) } /// Returns a slice containing the raw values. pub(crate) fn as_slice(&self) -> &[u8] { - &self.raw + self.0.as_slice() } /// Returns whether the specified feature flag is set. @@ -208,23 +172,7 @@ impl Features { /// # Ok(()) } /// ``` pub fn check(&self, bit: usize) -> bool { - let byte = bit / 8; - - if byte >= self.raw.len() { - // Unset bits are false. - false - } else { - (self.raw[byte] & (1 << (bit % 8))) != 0 - } - } - - /// Remove any trailing padding. - fn clear_padding(mut self) -> Self { - while self.raw.len() > 0 && self.raw[self.raw.len() - 1] == 0 { - self.raw.truncate(self.raw.len() - 1); - } - - self + self.0.get(bit) } /// Sets the specified feature flag. @@ -249,14 +197,8 @@ impl Features { /// # assert!(! f.supports_aead()); /// # Ok(()) } /// ``` - pub fn set(mut self, bit: usize) -> Self { - let byte = bit / 8; - while self.raw.len() <= byte { - self.raw.push(0); - } - self.raw[byte] |= 1 << (bit % 8); - - self.clear_padding() + pub fn set(self, bit: usize) -> Self { + Self(self.0.set(bit)) } /// Clears the specified feature flag. @@ -281,13 +223,8 @@ impl Features { /// # assert!(! f.supports_aead()); /// # Ok(()) } /// ``` - pub fn clear(mut self, bit: usize) -> Self { - let byte = bit / 8; - if byte < self.raw.len() { - self.raw[byte] &= !(1 << (bit % 8)); - } - - self.clear_padding() + pub fn clear(self, bit: usize) -> Self { + Self(self.0.clear(bit)) } /// Returns whether the MDC feature flag is set. @@ -436,11 +373,11 @@ mod tests { assert!(val.normalized_eq(&q)); // Add some padding to q. Make sure they are still equal. - q.raw.push(0); + q.0.raw.push(0); assert!(val != q); assert!(val.normalized_eq(&q)); - q.raw.push(0); + q.0.raw.push(0); assert!(val != q); assert!(val.normalized_eq(&q)); diff --git a/openpgp/src/types/mod.rs b/openpgp/src/types/mod.rs index 83e5ed0b..412b9f08 100644 --- a/openpgp/src/types/mod.rs +++ b/openpgp/src/types/mod.rs @@ -55,6 +55,8 @@ use quickcheck::{Arbitrary, Gen}; use crate::Error; use crate::Result; +mod bitfield; +use bitfield::Bitfield; mod compression_level; pub use compression_level::CompressionLevel; mod features; |