rust_car/
header.rs

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}