use alloc::boxed::Box;
use alloc::vec::Vec;
use std::io::{Cursor, Read};
use libarchive_oxide_core::transform::{Status, Step};
use libarchive_oxide_core::{Error, Result};
pub(crate) enum PullBridge<D> {
Buffering(Vec<u8>),
Decoding(Box<D>),
Done,
}
impl<D: Read> PullBridge<D> {
pub(crate) fn new() -> Self {
Self::Buffering(Vec::new())
}
pub(crate) fn push(&mut self, input: &[u8]) -> Step {
if let Self::Buffering(buf) = self {
buf.extend_from_slice(input);
Step {
consumed: input.len(),
produced: 0,
status: Status::NeedInput,
}
} else {
Step {
consumed: 0,
produced: 0,
status: Status::MoreOutput,
}
}
}
pub(crate) fn drain(
&mut self,
output: &mut [u8],
make: impl FnOnce(Cursor<Vec<u8>>) -> Result<D>,
) -> Result<Step> {
if let Self::Buffering(buf) = self {
let data = core::mem::take(buf);
*self = Self::Decoding(Box::new(make(Cursor::new(data))?));
}
match self {
Self::Decoding(decoder) => {
let n = decoder
.read(output)
.map_err(|_| Error::Malformed("decode error"))?;
if n == 0 {
*self = Self::Done;
Ok(Step {
consumed: 0,
produced: 0,
status: Status::Done,
})
} else {
Ok(Step {
consumed: 0,
produced: n,
status: Status::MoreOutput,
})
}
},
_ => Ok(Step {
consumed: 0,
produced: 0,
status: Status::Done,
}),
}
}
}