Skip to content

Commit e92540b

Browse files
committed
impl IntoIterator for SerializedSignature
This adds owned iterator for `SerializedSignature` and implements `IntoIterator`.
1 parent 7f2d3d2 commit e92540b

File tree

1 file changed

+140
-0
lines changed

1 file changed

+140
-0
lines changed

src/ecdsa/serialized_signature.rs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
//! unable to run on platforms without allocator. We implement a special type to encapsulate
66
//! serialized signatures and since it's a bit more complicated it has its own module.
77
8+
pub use into_iter::IntoIter;
9+
810
use core::{fmt, ops};
911
use crate::Error;
1012
use super::Signature;
@@ -62,6 +64,16 @@ impl ops::Deref for SerializedSignature {
6264

6365
impl Eq for SerializedSignature {}
6466

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+
6577
impl<'a> IntoIterator for &'a SerializedSignature {
6678
type IntoIter = core::slice::Iter<'a, u8>;
6779
type Item = &'a u8;
@@ -107,3 +119,131 @@ impl SerializedSignature {
107119
/// Check if the space is zero.
108120
pub fn is_empty(&self) -> bool { self.len() == 0 }
109121
}
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

Comments
 (0)