ipld_nostd/car/
header.rs

1use {
2	super::error::Error,
3	crate::{
4		alloc::{borrow::ToOwned, string::ToString},
5		cid::Cid,
6		dag,
7	},
8	alloc::vec::Vec,
9	serde::{Deserialize, Serialize},
10};
11
12/// A car header.
13#[derive(Debug, Clone, PartialEq, Eq)]
14#[non_exhaustive]
15pub enum CarHeader {
16	V1(CarHeaderV1),
17}
18
19impl CarHeader {
20	pub fn new_v1(roots: Vec<Cid>) -> Self {
21		Self::V1(roots.into())
22	}
23
24	pub fn decode(buffer: &[u8]) -> Result<Self, Error> {
25		let header: CarHeaderV1 =
26			dag::from_slice(buffer).map_err(|e| Error::Parsing(e.to_string()))?;
27
28		if header.roots.is_empty() {
29			return Err(Error::Parsing("empty CAR file".to_owned()));
30		}
31
32		if header.version != 1 {
33			return Err(Error::InvalidFile(
34				"Only CAR file version 1 is supported".to_string(),
35			));
36		}
37
38		Ok(CarHeader::V1(header))
39	}
40
41	pub fn encode(&self) -> Result<Vec<u8>, Error> {
42		match self {
43			CarHeader::V1(ref header) => {
44				let res = dag::to_vec(header).expect("vec");
45				Ok(res)
46			}
47		}
48	}
49
50	pub fn roots(&self) -> &[Cid] {
51		match self {
52			CarHeader::V1(header) => &header.roots,
53		}
54	}
55
56	pub fn version(&self) -> u64 {
57		match self {
58			CarHeader::V1(_) => 1,
59		}
60	}
61}
62
63/// CAR file header version 1.
64#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
65pub struct CarHeaderV1 {
66	pub roots: Vec<Cid>,
67	pub version: u64,
68}
69
70impl CarHeaderV1 {
71	/// Creates a new CAR file header
72	pub fn new(roots: Vec<Cid>, version: u64) -> Self {
73		Self { roots, version }
74	}
75}
76
77impl From<Vec<Cid>> for CarHeaderV1 {
78	fn from(roots: Vec<Cid>) -> Self {
79		Self { roots, version: 1 }
80	}
81}
82
83#[cfg(test)]
84mod tests {
85	use {super::*, crate::multihash::Multihash, ::alloc::*};
86
87	#[test]
88	fn symmetric_header_v1() {
89		let digest =
90			Multihash::wrap(0x1e, blake3::hash(b"test").as_bytes()).unwrap();
91		let cid = Cid::new_v1(0x71, digest);
92
93		let header = CarHeaderV1::from(vec![cid]);
94
95		let bytes = dag::to_vec(&header).unwrap();
96
97		assert_eq!(dag::from_slice::<CarHeaderV1>(&bytes).unwrap(), header);
98	}
99}