summaryrefslogtreecommitdiffstats
path: root/openpgp/src/parse/map.rs
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2018-10-23 15:55:19 +0200
committerJustus Winter <justus@sequoia-pgp.org>2018-10-23 16:15:35 +0200
commit0b0365c33484d7ab53cc8ec0ed4ae9d2ee05a827 (patch)
tree234814d5c0c0d2d4e1ef40d48f52ee50158b3500 /openpgp/src/parse/map.rs
parent96368044c5c43332621be9492610dd1784aefd51 (diff)
openpgp, tool: Improve iteration over packet maps.
- Using a concrete type allows us to change the implementation later. Furthermore, we avoid a heap allocation.
Diffstat (limited to 'openpgp/src/parse/map.rs')
-rw-r--r--openpgp/src/parse/map.rs82
1 files changed, 69 insertions, 13 deletions
diff --git a/openpgp/src/parse/map.rs b/openpgp/src/parse/map.rs
index c4ad9a23..134d4f47 100644
--- a/openpgp/src/parse/map.rs
+++ b/openpgp/src/parse/map.rs
@@ -4,7 +4,6 @@
//! charts the byte-stream, describing where the information was
//! extracted from.
-use std::iter;
use std::cmp;
/// Map created during parsing.
@@ -66,8 +65,8 @@ impl Map {
/// let ppo = PacketParserBuilder::from_bytes(msg)?
/// .map(true).finalize()?;
/// let map = ppo.unwrap().map.unwrap();
- /// assert_eq!(map.iter().collect::<Vec<(&str, &[u8])>>(),
- /// [("header", &b"\xcb\x12"[..]),
+ /// assert_eq!(map.iter().map(|f| (f.name, f.data)).collect::<Vec<(&str, &[u8])>>(),
+ /// [("frame", &b"\xcb\x12"[..]),
/// ("format", b"t"),
/// ("filename_len", b"\x00"),
/// ("date", b"\x00\x00\x00\x00"),
@@ -75,15 +74,72 @@ impl Map {
/// # Ok(())
/// # }
/// ```
- pub fn iter<'a>(&'a self)
- -> Box<'a + iter::Iterator<Item=(&'static str, &'a [u8])>> {
- let len = self.data.len();
- Box::new(
- iter::once(("header", self.header.as_slice()))
- .chain(self.entries.iter().map(move |e| {
- let start = cmp::min(len, e.offset);
- let end = cmp::min(len, e.offset + e.length);
- (e.field, &self.data[start..end])
- })))
+ pub fn iter<'a>(&'a self) -> Iter<'a> {
+ Iter::new(self)
+ }
+}
+
+/// Represents an entry in the map.
+#[derive(Clone, Debug)]
+pub struct Field<'a> {
+ /// Name of the field.
+ pub name: &'static str,
+ /// Offset of the field in the packet.
+ pub offset: usize,
+ /// Length of the field.
+ pub length: usize,
+ /// Value of the field.
+ pub data: &'a [u8],
+}
+
+impl<'a> Field<'a> {
+ fn new(map: &'a Map, i: usize) -> Field<'a> {
+ if i == 0 {
+ Field {
+ offset: 0,
+ length: map.header.len(),
+ name: "frame",
+ data: map.header.as_slice()
+ }
+ } else {
+ let len = map.data.len();
+ let e = &map.entries[i - 1];
+ let start = cmp::min(len, e.offset);
+ let end = cmp::min(len, e.offset + e.length);
+ Field {
+ offset: map.header.len() + e.offset,
+ length: e.length,
+ name: e.field,
+ data: &map.data[start..end],
+ }
+ }
+ }
+}
+
+/// An iterator over the map.
+pub struct Iter<'a> {
+ map: &'a Map,
+ i: usize,
+}
+
+impl<'a> Iter<'a> {
+ fn new(map: &'a Map) -> Iter<'a> {
+ Iter {
+ map: map,
+ i: 0,
+ }
+ }
+}
+
+impl<'a> Iterator for Iter<'a> {
+ type Item = Field<'a>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.i < self.map.entries.len() + 1 {
+ self.i += 1;
+ Some(Field::new(self.map, self.i - 1))
+ } else {
+ None
+ }
}
}