use alloc::vec::Vec;
use libarchive_oxide_core::transform::{Status, Step};
use libarchive_oxide_core::Result;
pub(crate) enum PushBridge {
Buffering(Vec<u8>),
Draining { data: Vec<u8>, pos: usize },
Done,
}
impl PushBridge {
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],
compress: impl FnOnce(&[u8]) -> Result<Vec<u8>>,
) -> Result<Step> {
if let Self::Buffering(buf) = self {
let plain = core::mem::take(buf);
*self = Self::Draining {
data: compress(&plain)?,
pos: 0,
};
}
match self {
Self::Draining { data, pos } => {
let remaining = data.len() - *pos;
if remaining == 0 || output.is_empty() {
if remaining == 0 {
*self = Self::Done;
return Ok(Step {
consumed: 0,
produced: 0,
status: Status::Done,
});
}
return Ok(Step {
consumed: 0,
produced: 0,
status: Status::MoreOutput,
});
}
let n = remaining.min(output.len());
output[..n].copy_from_slice(&data[*pos..*pos + n]);
*pos += n;
Ok(Step {
consumed: 0,
produced: n,
status: Status::MoreOutput,
})
},
_ => Ok(Step {
consumed: 0,
produced: 0,
status: Status::Done,
}),
}
}
}