1use cid::Cid;
2use ipld::{pb::DagPbCodec, prelude::Codec};
3
4use crate::{
5 error::CarError,
6 utils::{empty_pb_cid, pb_cid},
7 CarHeader, Ipld,
8};
9
10mod writer_v1;
11pub(crate) use writer_v1::CarWriterV1;
12
13pub enum WriteStream<'bs> {
14 Bytes(&'bs [u8]),
15 End,
16}
17
18pub trait CarWriter {
19 fn write_block<T>(&mut self, cid: Cid, data: T) -> Result<(), CarError>
20 where
21 T: AsRef<[u8]>;
22
23 fn stream_block<F, R>(
24 &mut self,
25 cid_f: F,
26 stream_len: usize,
27 r: &mut R,
28 ) -> Result<Cid, CarError>
29 where
30 R: std::io::Read + std::io::Seek,
31 F: FnMut(WriteStream) -> Option<Result<Cid, CarError>>;
32
33 fn write_ipld(&mut self, ipld: Ipld, hasher_codec: multicodec::Codec) -> Result<Cid, CarError> {
34 match ipld {
35 Ipld::Bytes(buf) => {
36 let file_cid = crate::utils::raw_cid(&buf, hasher_codec);
37 self.write_block(file_cid, &buf)?;
38 Ok(file_cid)
39 }
40 fs_ipld @ ipld::Ipld::Map(_) => {
41 let bs: Vec<u8> = DagPbCodec
42 .encode(&fs_ipld)
43 .map_err(|e| CarError::Parsing(e.to_string()))?;
44 let cid = pb_cid(&bs, hasher_codec);
45 self.write_block(cid, &bs)?;
46 Ok(cid)
47 }
48 _ => Err(CarError::Parsing("Not support write ipld.".to_lowercase())),
49 }
50 }
51
52 fn rewrite_header(&mut self, header: CarHeader) -> Result<(), CarError>;
53
54 fn flush(&mut self) -> Result<(), CarError>;
55}
56
57pub fn new_v1<W>(inner: W, header: CarHeader) -> Result<impl CarWriter, CarError>
58where
59 W: std::io::Write + std::io::Seek,
60{
61 Ok(CarWriterV1::new(inner, header))
62}
63
64pub fn new_v1_default_roots<W>(
65 inner: W,
66 hasher_codec: multicodec::Codec,
67) -> Result<impl CarWriter, CarError>
68where
69 W: std::io::Write + std::io::Seek,
70{
71 Ok(CarWriterV1::new(
72 inner,
73 CarHeader::new_v1(vec![empty_pb_cid(hasher_codec)]),
74 ))
75}