summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-07-28 14:53:36 +0200
committerJustus Winter <justus@sequoia-pgp.org>2020-07-28 14:53:36 +0200
commit6a7074bdf55b48c9e4598e3fff32b360537ea373 (patch)
tree86bd510b49674a446af25672226e790587c27ed5
parent52d3a63f1f0c0ad130f9a8351ef591aed28004ca (diff)
openpgp: Extract the Bitfield type from struct Features.
-rw-r--r--openpgp/src/types/bitfield.rs111
-rw-r--r--openpgp/src/types/features.rs93
-rw-r--r--openpgp/src/types/mod.rs2
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;