use std::convert::TryFrom;
use crate::{
Result,
Packet,
PacketPile,
};
use crate::parse::{
PacketParserBuilder,
PacketParserEOF,
PacketParserResult,
PacketParser,
Parse,
Cookie
};
use buffered_reader::BufferedReader;
#[derive(Debug)]
pub struct PacketPileParser<'a> {
ppr: PacketParserResult<'a>,
pile: PacketPile,
}
assert_send_and_sync!(PacketPileParser<'_>);
impl<'a> TryFrom<PacketParserBuilder<'a>> for PacketPileParser<'a> {
type Error = anyhow::Error;
fn try_from(ppb: PacketParserBuilder<'a>) -> Result<PacketPileParser<'a>> {
Self::from_packet_parser(ppb.build()?)
}
}
impl<'a> Parse<'a, PacketPileParser<'a>> for PacketPileParser<'a> {
fn from_buffered_reader<R>(reader: R) -> Result<PacketPileParser<'a>>
where
R: BufferedReader<Cookie> + 'a
{
PacketPileParser::from_cookie_reader(reader.into_boxed())
}
}
impl<'a> crate::seal::Sealed for PacketPileParser<'a> {}
impl<'a> PacketPileParser<'a> {
fn from_packet_parser(ppr: PacketParserResult<'a>)
-> Result<PacketPileParser<'a>>
{
Ok(PacketPileParser {
pile: Default::default(),
ppr,
})
}
pub(crate) fn from_cookie_reader(bio: Box<dyn BufferedReader<Cookie> + 'a>)
-> Result<PacketPileParser<'a>> {
Self::from_packet_parser(PacketParser::from_cookie_reader(bio)?)
}
fn insert_packet(&mut self, packet: Packet, position: isize) {
let mut container = self.pile.top_level_mut();
assert!(position >= 0);
for i in 0..position {
let tmp = container;
let packets_len = tmp.children_ref().expect("is a container").len();
let p = &mut tmp.children_mut()
.expect("is a container")
[packets_len - 1];
if p.children().expect("is a container").next().is_none() {
assert!(i == position - 1,
"Internal inconsistency while building message.");
}
container = p.container_mut().unwrap();
}
container.children_mut().unwrap().push(packet);
}
pub fn packet(&self)
-> std::result::Result<&PacketParser<'a>, &PacketParserEOF>
{
self.ppr.as_ref()
}
pub fn packet_mut<>(&mut self)
-> std::result::Result<&mut PacketParser<'a>,
&mut PacketParserEOF<'a>>
{
self.ppr.as_mut()
}
pub fn recurse(&mut self) -> Result<()> {
match self.ppr.take() {
PacketParserResult::Some(pp) => {
let recursion_depth = pp.recursion_depth();
let (packet, ppr) = pp.recurse()?;
self.insert_packet(
packet,
recursion_depth as isize);
self.ppr = ppr;
}
eof @ PacketParserResult::EOF(_) => {
self.ppr = eof;
}
}
Ok(())
}
pub fn next(&mut self) -> Result<()> {
match self.ppr.take() {
PacketParserResult::Some(pp) => {
let recursion_depth = pp.recursion_depth();
let (packet, ppr) = pp.next()?;
self.insert_packet(
packet,
recursion_depth as isize);
self.ppr = ppr;
},
eof @ PacketParserResult::EOF(_) => {
self.ppr = eof
},
}
Ok(())
}
pub fn recursion_depth(&self) -> Option<isize> {
if let PacketParserResult::Some(ref pp) = self.ppr {
Some(pp.recursion_depth())
} else {
None
}
}
pub fn is_done(&self) -> bool {
self.ppr.is_eof()
}
pub fn finish(self) -> PacketPile {
self.pile
}
}
#[test]
fn test_recurse() -> Result<()> {
let mut count = 0;
let mut ppp =
PacketPileParser::from_bytes(crate::tests::key("public-key.pgp"))?;
while ppp.packet().is_ok() {
count += 1;
ppp.recurse().unwrap();
}
assert_eq!(count, 61);
let pp = ppp.finish();
assert_eq!(pp.children().count(), 61);
Ok(())
}
#[test]
fn test_next() -> Result<()> {
let mut count = 0;
let mut ppp =
PacketPileParser::from_bytes(crate::tests::key("public-key.pgp"))?;
while ppp.packet().is_ok() {
count += 1;
ppp.next().unwrap();
}
assert_eq!(count, 61);
let pp = ppp.finish();
assert_eq!(pp.children().count(), 61);
Ok(())
}
#[cfg(feature = "compression-deflate")]
#[test]
fn message_parser_reader_interface() {
use std::io::Read;
let expected = crate::tests::manifesto();
let mut ppp = PacketPileParser::from_bytes(
crate::tests::message("compressed-data-algo-1.pgp")).unwrap();
let mut count = 0;
while let Ok(pp) = ppp.packet_mut() {
if let Packet::Literal(_) = pp.packet {
assert_eq!(count, 1);
for i in 0..expected.len() {
let mut buf = [0u8; 1];
let r = pp.read(&mut buf).unwrap();
assert_eq!(r, 1);
assert_eq!(buf[0], expected[i]);
}
let mut buf = [0u8; 1];
let r = pp.read(&mut buf).unwrap();
assert_eq!(r, 0);
}
ppp.recurse().unwrap();
count += 1;
}
assert_eq!(count, 2);
}