1mod header_v1;
2use std::io;
3
4pub(crate) use header_v1::CarHeaderV1;
5
6use cid::Cid;
7use ipld::prelude::Codec;
8use ipld_cbor::DagCborCodec;
9
10use crate::{error::CarError, reader::read_block};
11
12#[derive(Clone, Debug)]
13pub enum CarHeader {
14 V1(CarHeaderV1),
15 V2(),
16}
17
18impl CarHeader {
19 pub fn new_v1(roots: Vec<Cid>) -> Self {
20 CarHeader::V1(CarHeaderV1::new(roots))
21 }
22
23 pub fn roots(&self) -> Vec<Cid> {
24 match *self {
25 CarHeader::V1(ref v1) => v1.roots.clone(),
26 CarHeader::V2() => todo!(),
27 }
28 }
29
30 pub fn read_header<R>(r: R) -> Result<CarHeader, CarError>
31 where
32 R: io::Read + io::Seek,
33 {
34 let data = match read_block(r) {
35 Ok(Some(d)) => d,
36 Ok(None) => return Err(CarError::Parsing("Invalid Header".into())),
37 Err(e) => return Err(e),
38 };
39 let header = CarHeader::decode(&data[..])?;
40 Ok(header)
41 }
42
43 pub fn decode(buf: &[u8]) -> Result<CarHeader, CarError> {
44 let header: CarHeaderV1 = DagCborCodec
45 .decode(buf)
46 .map_err(|e| CarError::Parsing(e.to_string()))?;
47 if header.roots.is_empty() {
48 return Err(CarError::Parsing("car roots is empty".to_owned()));
49 }
50 if header.version != 1 {
51 return Err(CarError::InvalidFile(
52 "Now CAR version 1 is supported only".to_string(),
53 ));
54 }
55 Ok(CarHeader::V1(header))
56 }
57
58 pub fn encode(&self) -> Result<Vec<u8>, CarError> {
59 match *self {
60 CarHeader::V1(ref v1) => {
61 let data = DagCborCodec
62 .encode(v1)
63 .map_err(|e| CarError::Parsing(e.to_string()))?;
64 Ok(data)
65 }
66 CarHeader::V2() => todo!(),
67 }
68 }
69}