sequoia_openpgp/types/
bitfield.rs

1//! A variable-sized set of boolean flags.
2
3/// A variable-sized set of boolean flags.
4///
5/// This encodes flags in signature subpackets such as [`Features`]
6/// and [`KeyFlags`].  The `Bitfield` grows to accommodate all bits
7/// that are set, and querying a bit outside the allocated space will
8/// return `false`.  Note that it will not automatically shrink if
9/// clearing a bit would leave trailing bytes to be zero.  To do that,
10/// explicitly call [`Bitfield::canonicalize`].
11///
12///   [`Features`]: crate::types::Features
13///   [`KeyFlags`]: crate::types::KeyFlags
14#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct Bitfield {
16    raw: Vec<u8>,
17}
18
19impl From<Vec<u8>> for Bitfield {
20    fn from(raw: Vec<u8>) -> Self {
21        Self { raw }
22    }
23}
24
25impl AsRef<[u8]> for Bitfield {
26    fn as_ref(&self) -> &[u8] {
27        self.as_bytes()
28    }
29}
30
31impl AsMut<[u8]> for Bitfield {
32    fn as_mut(&mut self) -> &mut [u8] {
33        self.as_bytes_mut()
34    }
35}
36
37impl Bitfield {
38    /// Returns all bits that are set starting from bit 0, the
39    /// least-significant bit in the left-most byte.
40    ///
41    /// # Examples
42    ///
43    /// ```rust
44    /// # use sequoia_openpgp::types::Bitfield;
45    /// let f = Bitfield::from(vec![0b0000_0001, 0b0000_0010]);
46    /// let mut i = f.iter_set();
47    /// assert_eq!(i.next(), Some(0));
48    /// assert_eq!(i.next(), Some(9));
49    /// assert_eq!(i.next(), None);
50    /// ```
51    pub fn iter_set(&self) -> impl Iterator<Item = usize> + Send + Sync + '_
52    {
53        self.raw.iter()
54            .flat_map(|b| {
55                (0..8).into_iter().map(move |i| {
56                    b & (1 << i) != 0
57                })
58            })
59            .enumerate()
60            .filter_map(|(i, v)| if v { Some(i) } else { None })
61    }
62
63    /// Returns the number of trailing zero bytes.
64    ///
65    /// # Examples
66    ///
67    /// ```rust
68    /// # use sequoia_openpgp::types::Bitfield;
69    /// let mut f = Bitfield::from(vec![0b0000_0001]);
70    /// assert!(f.padding_bytes().is_none());
71    /// f.clear(0);
72    /// assert_eq!(f.padding_bytes().unwrap().get(), 1);
73    /// f.canonicalize();
74    /// assert!(f.padding_bytes().is_none());
75    /// ```
76    pub fn padding_bytes(&self) -> Option<std::num::NonZeroUsize> {
77        std::num::NonZeroUsize::new(
78            self.raw.iter().rev().take_while(|b| **b == 0).count())
79    }
80
81    /// Compares two feature sets for semantic equality.
82    ///
83    /// Returns true if both sets have the same flags set, i.e. this
84    /// function ignores any trailing zero bytes.
85    ///
86    /// # Examples
87    ///
88    /// ```rust
89    /// # use sequoia_openpgp::types::Bitfield;
90    /// let f = Bitfield::from(vec![0b0000_0001]);
91    /// let g = Bitfield::from(vec![0b0000_0001, 0b0000_0000]);
92    /// assert!(f != g);
93    /// assert!(f.normalized_eq(&g));
94    /// ```
95    pub fn normalized_eq(&self, other: &Self) -> bool {
96        let (small, big) = if self.raw.len() < other.raw.len() {
97            (self, other)
98        } else {
99            (other, self)
100        };
101
102        for (s, b) in small.raw.iter().zip(big.raw.iter()) {
103            if s != b {
104                return false;
105            }
106        }
107
108        for &b in &big.raw[small.raw.len()..] {
109            if b != 0 {
110                return false;
111            }
112        }
113
114        true
115    }
116
117    /// Returns a slice containing the raw values.
118    ///
119    /// # Examples
120    ///
121    /// ```rust
122    /// # use sequoia_openpgp::types::Bitfield;
123    /// let mut f = Bitfield::default();
124    /// assert_eq!(f.as_bytes(), &[]);
125    /// f.set(0);
126    /// assert_eq!(f.as_bytes(), &[0b0000_0001]);
127    /// ```
128    pub fn as_bytes(&self) -> &[u8] {
129        &self.raw
130    }
131
132    /// Returns a mutable slice containing the raw values.
133    ///
134    /// # Examples
135    ///
136    /// ```rust
137    /// # use sequoia_openpgp::types::Bitfield;
138    /// let mut f = Bitfield::from(vec![0b0000_0000]);
139    /// assert_eq!(f.get(0), false);
140    /// f.as_bytes_mut()[0] = 0b0000_0001;
141    /// assert_eq!(f.get(0), true);
142    /// ```
143    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
144        &mut self.raw
145    }
146
147    /// Returns whether the specified flag is set.
148    ///
149    /// # Examples
150    ///
151    /// ```rust
152    /// # use sequoia_openpgp::types::Bitfield;
153    /// let f = Bitfield::default();
154    /// assert_eq!(f.get(0), false);
155    /// assert_eq!(f.get(23), false);
156    ///
157    /// let f = Bitfield::from(vec![0b0000_0001]);
158    /// assert_eq!(f.get(0), true);
159    /// ```
160    pub fn get(&self, bit: usize) -> bool {
161        let byte = bit / 8;
162
163        if byte >= self.raw.len() {
164            // Unset bits are false.
165            false
166        } else {
167            (self.raw[byte] & (1 << (bit % 8))) != 0
168        }
169    }
170
171    /// Canonicalize by removing any trailing zero bytes.
172    ///
173    /// # Examples
174    ///
175    /// ```rust
176    /// # use sequoia_openpgp::types::Bitfield;
177    /// let mut f = Bitfield::from(vec![0b0000_0001]);
178    /// assert!(f.padding_bytes().is_none());
179    /// f.clear(0);
180    /// assert_eq!(f.padding_bytes().unwrap().get(), 1);
181    /// f.canonicalize();
182    /// assert!(f.padding_bytes().is_none());
183    /// ```
184    pub fn canonicalize(&mut self) {
185        while !self.raw.is_empty() && self.raw[self.raw.len() - 1] == 0 {
186            self.raw.truncate(self.raw.len() - 1);
187        }
188    }
189
190    /// Sets the specified flag.
191    ///
192    /// # Examples
193    ///
194    /// ```rust
195    /// # use sequoia_openpgp::types::Bitfield;
196    /// let mut f = Bitfield::default();
197    /// assert_eq!(f.get(0), false);
198    /// f.set(0);
199    /// assert_eq!(f.get(0), true);
200    /// ```
201    pub fn set(&mut self, bit: usize) {
202        let byte = bit / 8;
203        while self.raw.len() <= byte {
204            self.raw.push(0);
205        }
206        self.raw[byte] |= 1 << (bit % 8);
207    }
208
209    /// Clears the specified flag.
210    ///
211    /// Note: This does not implicitly canonicalize the bit field.  To
212    /// do that, invoke [`Bitfield::canonicalize`].
213    ///
214    /// # Examples
215    ///
216    /// ```rust
217    /// # use sequoia_openpgp::types::Bitfield;
218    /// let mut f = Bitfield::from(vec![0b0000_0001]);
219    /// assert_eq!(f.get(0), true);
220    /// f.clear(0);
221    /// assert_eq!(f.get(0), false);
222    /// assert_eq!(f.padding_bytes().unwrap().get(), 1);
223    /// ```
224    pub fn clear(&mut self, bit: usize) {
225        let byte = bit / 8;
226        if byte < self.raw.len() {
227            self.raw[byte] &= !(1 << (bit % 8));
228        }
229    }
230}