//! A variable-sized set of boolean flags. /// A variable-sized set of boolean flags. /// /// This encodes flags in signature subpackets such as [`Features`] /// and [`KeyFlags`]. The `Bitfield` grows to accommodate all bits /// that are set, and querying a bit outside the allocated space will /// return `false`. Note that it will not automatically shrink if /// clearing a bit would leave trailing bytes to be zero. To do that, /// explicitly call [`Bitfield::canonicalize`]. /// /// [`Features`]: crate::types::Features /// [`KeyFlags`]: crate::types::KeyFlags #[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Bitfield { raw: Vec, } impl From> for Bitfield { fn from(raw: Vec) -> Self { Self { raw } } } impl AsRef<[u8]> for Bitfield { fn as_ref(&self) -> &[u8] { self.as_bytes() } } impl AsMut<[u8]> for Bitfield { fn as_mut(&mut self) -> &mut [u8] { self.as_bytes_mut() } } impl Bitfield { /// Returns all bits that are set starting from bit 0, the /// least-significant bit in the left-most byte. /// /// # Examples /// /// ```rust /// # use sequoia_openpgp::types::Bitfield; /// let f = Bitfield::from(vec![0b0000_0001, 0b0000_0010]); /// let mut i = f.iter_set(); /// assert_eq!(i.next(), Some(0)); /// assert_eq!(i.next(), Some(9)); /// assert_eq!(i.next(), None); /// ``` pub fn iter_set(&self) -> impl Iterator + Send + Sync + '_ { 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 }) } /// Returns the number of trailing zero bytes. /// /// # Examples /// /// ```rust /// # use sequoia_openpgp::types::Bitfield; /// let mut f = Bitfield::from(vec![0b0000_0001]); /// assert!(f.padding_bytes().is_none()); /// f.clear(0); /// assert_eq!(f.padding_bytes().unwrap().get(), 1); /// f.canonicalize(); /// assert!(f.padding_bytes().is_none()); /// ``` pub fn padding_bytes(&self) -> Option { std::num::NonZeroUsize::new( self.raw.iter().rev().take_while(|b| **b == 0).count()) } /// Compares two feature sets for semantic equality. /// /// Returns true if both sets have the same flags set, i.e. this /// function ignores any trailing zero bytes. /// /// # Examples /// /// ```rust /// # use sequoia_openpgp::types::Bitfield; /// let f = Bitfield::from(vec![0b0000_0001]); /// let g = Bitfield::from(vec![0b0000_0001, 0b0000_0000]); /// assert!(f != g); /// assert!(f.normalized_eq(&g)); /// ``` 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. /// /// # Examples /// /// ```rust /// # use sequoia_openpgp::types::Bitfield; /// let mut f = Bitfield::default(); /// assert_eq!(f.as_bytes(), &[]); /// f.set(0); /// assert_eq!(f.as_bytes(), &[0b0000_0001]); /// ``` pub fn as_bytes(&self) -> &[u8] { &self.raw } /// Returns a mutable slice containing the raw values. /// /// # Examples /// /// ```rust /// # use sequoia_openpgp::types::Bitfield; /// let mut f = Bitfield::from(vec![0b0000_0000]); /// assert_eq!(f.get(0), false); /// f.as_bytes_mut()[0] = 0b0000_0001; /// assert_eq!(f.get(0), true); /// ``` pub fn as_bytes_mut(&mut self) -> &mut [u8] { &mut self.raw } /// Returns whether the specified flag is set. /// /// # Examples /// /// ```rust /// # use sequoia_openpgp::types::Bitfield; /// let f = Bitfield::default(); /// assert_eq!(f.get(0), false); /// assert_eq!(f.get(23), false); /// /// let f = Bitfield::from(vec![0b0000_0001]); /// assert_eq!(f.get(0), true); /// ``` 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 } } /// Canonicalize by removing any trailing zero bytes. /// /// # Examples /// /// ```rust /// # use sequoia_openpgp::types::Bitfield; /// let mut f = Bitfield::from(vec![0b0000_0001]); /// assert!(f.padding_bytes().is_none()); /// f.clear(0); /// assert_eq!(f.padding_bytes().unwrap().get(), 1); /// f.canonicalize(); /// assert!(f.padding_bytes().is_none()); /// ``` pub fn canonicalize(&mut self) { while !self.raw.is_empty() && self.raw[self.raw.len() - 1] == 0 { self.raw.truncate(self.raw.len() - 1); } } /// Sets the specified flag. /// /// # Examples /// /// ```rust /// # use sequoia_openpgp::types::Bitfield; /// let mut f = Bitfield::default(); /// assert_eq!(f.get(0), false); /// f.set(0); /// assert_eq!(f.get(0), true); /// ``` pub fn set(&mut self, bit: usize) { let byte = bit / 8; while self.raw.len() <= byte { self.raw.push(0); } self.raw[byte] |= 1 << (bit % 8); } /// Clears the specified flag. /// /// Note: This does not implicitly canonicalize the bit field. To /// do that, invoke [`Bitfield::canonicalize`]. /// /// # Examples /// /// ```rust /// # use sequoia_openpgp::types::Bitfield; /// let mut f = Bitfield::from(vec![0b0000_0001]); /// assert_eq!(f.get(0), true); /// f.clear(0); /// assert_eq!(f.get(0), false); /// assert_eq!(f.padding_bytes().unwrap().get(), 1); /// ``` pub fn clear(&mut self, bit: usize) { let byte = bit / 8; if byte < self.raw.len() { self.raw[byte] &= !(1 << (bit % 8)); } } }