diff options
author | Neal H. Walfield <neal@pep.foundation> | 2018-04-30 23:00:44 +0200 |
---|---|---|
committer | Neal H. Walfield <neal@pep.foundation> | 2018-04-30 23:03:58 +0200 |
commit | 32c78a7358ba3c2b1290ae5dc298d885d098fe1d (patch) | |
tree | e612808c05220192ba4964c3ed26deb099d21d17 | |
parent | e159c7ae2f92e746b4980ab6fbfc7a03a1483106 (diff) |
openpgp: Provide a function to turn a PacketParser into an iterator.
- Note: when turned into an iterator, packets are fully buffered.
-rw-r--r-- | openpgp/src/lib.rs | 10 | ||||
-rw-r--r-- | openpgp/src/parse/parse.rs | 68 |
2 files changed, 78 insertions, 0 deletions
diff --git a/openpgp/src/lib.rs b/openpgp/src/lib.rs index 04dd73d8..72aa381b 100644 --- a/openpgp/src/lib.rs +++ b/openpgp/src/lib.rs @@ -158,6 +158,16 @@ pub enum Error { Io(#[cause] io::Error), } +/// Returns any pending error. +/// +/// This interface is useful, because using an iterator, the caller +/// cannot distinguish between no more items and an error. +pub trait IterError { + fn error(&mut self) -> Option<failure::Error> { + None + } +} + // A helpful debugging function. #[allow(dead_code)] fn to_hex(s: &[u8], pretty: bool) -> String { diff --git a/openpgp/src/parse/parse.rs b/openpgp/src/parse/parse.rs index 60204bd2..c7c2bb5d 100644 --- a/openpgp/src/parse/parse.rs +++ b/openpgp/src/parse/parse.rs @@ -2515,7 +2515,75 @@ mod test { } } } + +/// An iterator over a packet stream. +/// +/// This iterator recurses into any containers. +/// +/// Because parsing packets may result in an error, users of this +/// iterator should call iter.error() when they receive None to +/// determine if the iterator stopped due to an error or because the +/// packet stream was really exhausted. +pub struct PacketParserIter<'a> { + ppo: Option<PacketParser<'a>>, + error: Option<failure::Error>, +} + +impl<'a> Iterator for PacketParserIter<'a> { + type Item = Packet; + + fn next(&mut self) -> Option<Self::Item> { + if self.error.is_some() { + return None; + } + + let ppo = self.ppo.take(); + if let Some(pp) = ppo { + match pp.recurse() { + Ok((packet, _, ppo_tmp, _)) => { + self.ppo = ppo_tmp; + Some(packet) + }, + Err(err) => { + self.error = Some(err); + None + }, + } + } else { + None + } + } +} + +impl<'a> IterError for PacketParserIter<'a> { + /// Returns any pending error. + fn error(&mut self) -> Option<failure::Error> { + self.error.take() + } +} + +impl<'a> IntoIterator for PacketParser<'a> { + type Item = Packet; + type IntoIter = PacketParserIter<'a>; + + fn into_iter(self) -> Self::IntoIter { + PacketParserIter { + ppo: Some(self), + error: None, + } + } +} +#[test] +fn packet_parser_iter_test() { + let pp = PacketParser::from_file( + path_to("compressed-data-algo-1.gpg")).unwrap().unwrap(); + + let tags : Vec<Tag> = pp.into_iter().map(|p| p.tag()).collect(); + assert_eq!(&[ Tag::CompressedData, Tag::Literal ][..], + &tags[..]); +} + impl Message { // Reads all of the packets from a `PacketParser`, and turns them // into a message. Note: this assumes that `ppo` points to a |