use crate::config::Compression;
use crate::framer::{Codec, ObjectFramer};
use crate::split::SplitRange;
use crate::trim::RangeTrim;
use bytes::Bytes;
use spate_core::framing::RecordFramer;
use std::io;
use std::sync::Arc;
pub type MakeFramer = Arc<dyn Fn() -> Box<dyn RecordFramer> + Send + Sync>;
pub fn frame_objects(
compression: Compression,
make_framer: MakeFramer,
objects: &[(String, Vec<Bytes>)],
) -> io::Result<usize> {
let mut framer = ObjectFramer::new(make_framer);
let mut records = 0;
for (key, chunks) in objects {
framer.begin_object(Codec::resolve(compression, key))?;
for chunk in chunks {
framer.push_chunk(chunk.clone())?;
loop {
while framer.pop_record().is_some() {
records += 1;
}
if !framer.has_pending_input() {
break;
}
framer.pump()?;
}
}
framer.finish_object()?;
while framer.pop_record().is_some() {
records += 1;
}
}
Ok(records)
}
pub fn frame_range(
make_framer: MakeFramer,
object: &[u8],
start: u64,
end: u64,
delimiter: u8,
range_bytes: u64,
chunk_bytes: usize,
) -> io::Result<usize> {
let size = object.len() as u64;
assert!(
start < end && end <= size,
"[{start}, {end}) is not a range of the object"
);
let mut trim = RangeTrim::new(SplitRange::new(start, end, delimiter), size);
let mut framer = ObjectFramer::new(make_framer);
let mut records = 0;
framer.begin_object(Codec::Plain)?;
let mut pos = trim.first_byte();
while let Some(window_end) = trim.next_window(pos, range_bytes, chunk_bytes as u64) {
let window = Bytes::copy_from_slice(&object[pos as usize..window_end as usize]);
let mut owned = trim.feed(pos, window);
while !owned.is_empty() {
let chunk = owned.split_to(owned.len().min(chunk_bytes));
framer.push_chunk(chunk)?;
while framer.pop_record().is_some() {
records += 1;
}
debug_assert!(
!framer.has_pending_input(),
"a plain chunk decodes in one step"
);
}
pos = window_end;
}
framer.finish_object()?;
while framer.pop_record().is_some() {
records += 1;
}
Ok(records)
}