use alloc::vec::Vec;
#[derive(Default)]
pub struct Writer<'a> {
owned: Vec<u8>,
chunks: Vec<Chunk<'a>>,
}
impl<'a> Writer<'a> {
pub(crate) fn new() -> Self {
Writer::default()
}
pub(crate) fn put_share(&mut self, data: &'a [u8]) {
self.chunks.push(Chunk::Borrowed(data));
}
pub(crate) fn put_copy(&mut self, data: &[u8]) {
if !matches!(self.chunks.last(), Some(Chunk::Owned { .. })) {
self.chunks.push(Chunk::Owned { offset: self.owned.len(), length: 0 });
}
let length = match self.chunks.last_mut() {
Some(Chunk::Owned { length, .. }) => length,
_ => unreachable!(),
};
self.owned.extend_from_slice(data);
*length += data.len();
}
pub(crate) fn finalize(self, data: &mut Vec<u8>) {
data.reserve_exact(self.chunks.iter().map(|x| x.len()).sum());
for chunk in self.chunks {
data.extend_from_slice(chunk.slice(&self.owned));
}
}
}
enum Chunk<'a> {
Owned { offset: usize, length: usize },
Borrowed(&'a [u8]),
}
impl<'a> Chunk<'a> {
fn slice(&self, owned: &'a [u8]) -> &'a [u8] {
match *self {
Chunk::Owned { offset, length } => &owned[offset ..][.. length],
Chunk::Borrowed(x) => x,
}
}
fn len(&self) -> usize {
match *self {
Chunk::Owned { length, .. } => length,
Chunk::Borrowed(x) => x.len(),
}
}
}