mod header_v1;
use std::io;
pub(crate) use header_v1::CarHeaderV1;
use cid::Cid;
use ipld::prelude::Codec;
use ipld_cbor::DagCborCodec;
use crate::{error::CarError, reader::read_block};
#[derive(Clone, Debug)]
pub enum CarHeader {
V1(CarHeaderV1),
V2(),
}
impl CarHeader {
pub fn new_v1(roots: Vec<Cid>) -> Self {
CarHeader::V1(CarHeaderV1::new(roots))
}
pub fn roots(&self) -> Vec<Cid> {
match *self {
CarHeader::V1(ref v1) => v1.roots.clone(),
CarHeader::V2() => todo!(),
}
}
pub fn read_header<R>(r: R) -> Result<CarHeader, CarError>
where
R: io::Read + io::Seek,
{
let data = match read_block(r) {
Ok(Some(d)) => d,
Ok(None) => return Err(CarError::Parsing("Invalid Header".into())),
Err(e) => return Err(e),
};
let header = CarHeader::decode(&data[..])?;
Ok(header)
}
pub fn decode(buf: &[u8]) -> Result<CarHeader, CarError> {
let header: CarHeaderV1 = DagCborCodec
.decode(buf)
.map_err(|e| CarError::Parsing(e.to_string()))?;
if header.roots.is_empty() {
return Err(CarError::Parsing("car roots is empty".to_owned()));
}
if header.version != 1 {
return Err(CarError::InvalidFile(
"Now CAR version 1 is supported only".to_string(),
));
}
Ok(CarHeader::V1(header))
}
pub fn encode(&self) -> Result<Vec<u8>, CarError> {
match *self {
CarHeader::V1(ref v1) => {
let data = DagCborCodec
.encode(v1)
.map_err(|e| CarError::Parsing(e.to_string()))?;
Ok(data)
}
CarHeader::V2() => todo!(),
}
}
}