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}