summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2018-04-30 23:00:44 +0200
committerNeal H. Walfield <neal@pep.foundation>2018-04-30 23:03:58 +0200
commit32c78a7358ba3c2b1290ae5dc298d885d098fe1d (patch)
treee612808c05220192ba4964c3ed26deb099d21d17
parente159c7ae2f92e746b4980ab6fbfc7a03a1483106 (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.rs10
-rw-r--r--openpgp/src/parse/parse.rs68
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