|
5 | 5 | //! unable to run on platforms without allocator. We implement a special type to encapsulate
|
6 | 6 | //! serialized signatures and since it's a bit more complicated it has its own module.
|
7 | 7 |
|
| 8 | +pub use into_iter::IntoIter; |
| 9 | + |
8 | 10 | use core::{fmt, ops};
|
9 | 11 | use crate::Error;
|
10 | 12 | use super::Signature;
|
@@ -62,6 +64,16 @@ impl ops::Deref for SerializedSignature {
|
62 | 64 |
|
63 | 65 | impl Eq for SerializedSignature {}
|
64 | 66 |
|
| 67 | +impl IntoIterator for SerializedSignature { |
| 68 | + type IntoIter = IntoIter; |
| 69 | + type Item = u8; |
| 70 | + |
| 71 | + #[inline] |
| 72 | + fn into_iter(self) -> Self::IntoIter { |
| 73 | + IntoIter::new(self) |
| 74 | + } |
| 75 | +} |
| 76 | + |
65 | 77 | impl<'a> IntoIterator for &'a SerializedSignature {
|
66 | 78 | type IntoIter = core::slice::Iter<'a, u8>;
|
67 | 79 | type Item = &'a u8;
|
@@ -107,3 +119,131 @@ impl SerializedSignature {
|
107 | 119 | /// Check if the space is zero.
|
108 | 120 | pub fn is_empty(&self) -> bool { self.len() == 0 }
|
109 | 121 | }
|
| 122 | + |
| 123 | +/// Separate mod to prevent outside code accidentally breaking invariants. |
| 124 | +mod into_iter { |
| 125 | + use super::*; |
| 126 | + |
| 127 | + /// Owned iterator over the bytes of [`SerializedSignature`] |
| 128 | + /// |
| 129 | + /// Created by [`IntoIterator::into_iter`] method. |
| 130 | + // allowed because of https://github.com/rust-lang/rust/issues/98348 |
| 131 | + #[allow(missing_copy_implementations)] |
| 132 | + #[derive(Debug, Clone)] |
| 133 | + pub struct IntoIter { |
| 134 | + signature: SerializedSignature, |
| 135 | + // invariant: pos <= signature.len() |
| 136 | + pos: usize, |
| 137 | + } |
| 138 | + |
| 139 | + impl IntoIter { |
| 140 | + #[inline] |
| 141 | + pub(crate) fn new(signature: SerializedSignature) -> Self { |
| 142 | + IntoIter { |
| 143 | + signature, |
| 144 | + // for all unsigned n: 0 <= n |
| 145 | + pos: 0, |
| 146 | + } |
| 147 | + } |
| 148 | + |
| 149 | + /// Returns the remaining bytes as a slice. |
| 150 | + /// |
| 151 | + /// This method is analogous to [`core::slice::Iter::as_slice`]. |
| 152 | + #[inline] |
| 153 | + pub fn as_slice(&self) -> &[u8] { |
| 154 | + &self.signature[self.pos..] |
| 155 | + } |
| 156 | + } |
| 157 | + |
| 158 | + impl Iterator for IntoIter { |
| 159 | + type Item = u8; |
| 160 | + |
| 161 | + #[inline] |
| 162 | + fn next(&mut self) -> Option<Self::Item> { |
| 163 | + let byte = *self.signature.get(self.pos)?; |
| 164 | + // can't overflow or break invariant because if pos is too large we return early |
| 165 | + self.pos += 1; |
| 166 | + Some(byte) |
| 167 | + } |
| 168 | + |
| 169 | + #[inline] |
| 170 | + fn size_hint(&self) -> (usize, Option<usize>) { |
| 171 | + // can't underlflow thanks to the invariant |
| 172 | + let len = self.signature.len() - self.pos; |
| 173 | + (len, Some(len)) |
| 174 | + } |
| 175 | + |
| 176 | + // override for speed |
| 177 | + #[inline] |
| 178 | + fn nth(&mut self, n: usize) -> Option<Self::Item> { |
| 179 | + if n >= self.len() { |
| 180 | + // upholds invariant becasue the values will be equal |
| 181 | + self.pos = self.signature.len(); |
| 182 | + None |
| 183 | + } else { |
| 184 | + // if n < signtature.len() - self.pos then n + self.pos < signature.len() which neither |
| 185 | + // overflows nor breaks the invariant |
| 186 | + self.pos += n; |
| 187 | + self.next() |
| 188 | + } |
| 189 | + } |
| 190 | + } |
| 191 | + |
| 192 | + impl ExactSizeIterator for IntoIter {} |
| 193 | + |
| 194 | + impl core::iter::FusedIterator for IntoIter {} |
| 195 | + |
| 196 | + impl DoubleEndedIterator for IntoIter { |
| 197 | + #[inline] |
| 198 | + fn next_back(&mut self) -> Option<Self::Item> { |
| 199 | + if self.pos == self.signature.len() { |
| 200 | + return None; |
| 201 | + } |
| 202 | + |
| 203 | + // if len is 0 then pos is also 0 thanks to the invariant so we would return before we |
| 204 | + // reach this |
| 205 | + let new_len = self.signature.len() - 1; |
| 206 | + let byte = self.signature[new_len]; |
| 207 | + self.signature.set_len(new_len); |
| 208 | + Some(byte) |
| 209 | + } |
| 210 | + } |
| 211 | +} |
| 212 | + |
| 213 | +#[cfg(test)] |
| 214 | +mod tests { |
| 215 | + use super::SerializedSignature; |
| 216 | + |
| 217 | + #[test] |
| 218 | + fn iterator_ops_are_homomorphic() { |
| 219 | + let mut fake_signature_data = [0; 72]; |
| 220 | + // fill it with numbers 0 - 71 |
| 221 | + for (i, byte) in fake_signature_data.iter_mut().enumerate() { |
| 222 | + // up to 72 |
| 223 | + *byte = i as u8; |
| 224 | + } |
| 225 | + |
| 226 | + let fake_signature = SerializedSignature { data: fake_signature_data, len: 72 }; |
| 227 | + |
| 228 | + let mut iter1 = fake_signature.into_iter(); |
| 229 | + let mut iter2 = fake_signature.iter(); |
| 230 | + |
| 231 | + // while let so we can compare size_hint and as_slice |
| 232 | + while let (Some(a), Some(b)) = (iter1.next(), iter2.next()) { |
| 233 | + assert_eq!(a, *b); |
| 234 | + assert_eq!(iter1.size_hint(), iter2.size_hint()); |
| 235 | + assert_eq!(iter1.as_slice(), iter2.as_slice()); |
| 236 | + } |
| 237 | + |
| 238 | + let mut iter1 = fake_signature.into_iter(); |
| 239 | + let mut iter2 = fake_signature.iter(); |
| 240 | + |
| 241 | + // manual next_back instead of rev() so that we can check as_slice() |
| 242 | + // if next_back is implemented correctly then rev() is also correct - provided by `core` |
| 243 | + while let (Some(a), Some(b)) = (iter1.next_back(), iter2.next_back()) { |
| 244 | + assert_eq!(a, *b); |
| 245 | + assert_eq!(iter1.size_hint(), iter2.size_hint()); |
| 246 | + assert_eq!(iter1.as_slice(), iter2.as_slice()); |
| 247 | + } |
| 248 | + } |
| 249 | +} |
0 commit comments