diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2018-10-23 15:55:19 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2018-10-23 16:15:35 +0200 |
commit | 0b0365c33484d7ab53cc8ec0ed4ae9d2ee05a827 (patch) | |
tree | 234814d5c0c0d2d4e1ef40d48f52ee50158b3500 /openpgp/src/parse/map.rs | |
parent | 96368044c5c43332621be9492610dd1784aefd51 (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.rs | 82 |
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 + } } } |