use std::io::Write;
use crate::cbor::{Cid, Encoder, encode_text_map};
use crate::car::{Block, CarError};
#[inline]
fn encode_varint_buf(mut value: u64, buf: &mut [u8; 10]) -> usize {
let mut i = 0;
loop {
let mut byte = (value & 0x7F) as u8;
value >>= 7;
if value != 0 {
byte |= 0x80;
}
buf[i] = byte;
i += 1;
if value == 0 {
break;
}
}
i
}
pub struct Writer<W: Write> {
writer: W,
}
impl<W: Write> Writer<W> {
pub fn new(mut writer: W, roots: &[Cid]) -> Result<Self, CarError> {
let mut header_buf = Vec::with_capacity(64 + roots.len() * 41);
{
let mut enc = Encoder::new(&mut header_buf);
let roots_snapshot = roots;
encode_text_map(&mut enc, &["roots", "version"], |enc, key| match key {
"roots" => {
enc.encode_array_header(roots_snapshot.len() as u64)?;
for cid in roots_snapshot {
enc.encode_cid(cid)?;
}
Ok(())
}
"version" => enc.encode_u64(1),
_ => Ok(()),
})?;
}
let mut vbuf = [0u8; 10];
let vlen = encode_varint_buf(header_buf.len() as u64, &mut vbuf);
writer.write_all(&vbuf[..vlen])?;
writer.write_all(&header_buf)?;
Ok(Writer { writer })
}
#[inline]
pub fn write_block(&mut self, block: &Block) -> Result<(), CarError> {
let cid_bytes = block.cid.to_bytes();
let block_len = cid_bytes.len() + block.data.len();
let mut vbuf = [0u8; 10];
let vlen = encode_varint_buf(block_len as u64, &mut vbuf);
self.writer.write_all(&vbuf[..vlen])?;
self.writer.write_all(&cid_bytes)?;
self.writer.write_all(&block.data)?;
Ok(())
}
pub fn finish(self) -> W {
self.writer
}
}