1pub mod zerocopy_serialization;
6
7use fprint::TypeFingerprint;
8use fuchsia_merkle::{Hash, MerkleVerifier};
9use serde::{Deserialize, Serialize};
10
11#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, TypeFingerprint)]
12pub struct BlobMetadataUnversioned {
13 pub hashes: Vec<[u8; 32]>,
14 pub chunk_size: u64,
15 pub compressed_offsets: Vec<u64>,
16 pub uncompressed_size: u64,
17}
18
19pub type BlobMetadata = BlobMetadataV53;
20pub type BlobFormat = BlobFormatV53;
21pub type MerkleLeaves = Vec<[u8; 32]>;
22
23#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, TypeFingerprint)]
24pub struct BlobMetadataV53 {
25 #[serde(with = "zerocopy_serialization")]
26 pub merkle_leaves: MerkleLeaves,
27 pub format: BlobFormatV53,
28}
29
30impl BlobMetadataV53 {
31 pub fn empty() -> Self {
32 Self { merkle_leaves: Vec::new(), format: BlobFormatV53::Uncompressed }
33 }
34
35 pub fn is_empty(&self) -> bool {
36 *self == Self::empty()
37 }
38
39 pub fn into_merkle_verifier(self, root: Hash) -> Result<MerkleVerifier, anyhow::Error> {
40 let hashes = if self.merkle_leaves.is_empty() {
41 Box::new([root])
42 } else {
43 self.merkle_leaves.into_iter().map(Into::into).collect::<Box<[Hash]>>()
44 };
45 Ok(MerkleVerifier::new(root, hashes)?)
46 }
47}
48
49impl From<BlobMetadataUnversioned> for BlobMetadataV53 {
50 fn from(old: BlobMetadataUnversioned) -> Self {
51 if old.compressed_offsets.is_empty() {
52 Self { merkle_leaves: old.hashes, format: BlobFormat::Uncompressed }
53 } else {
54 Self {
55 merkle_leaves: old.hashes,
56 format: BlobFormat::ChunkedZstd {
57 uncompressed_size: old.uncompressed_size,
58 chunk_size: old.chunk_size,
59 compressed_offsets: old.compressed_offsets,
60 },
61 }
62 }
63 }
64}
65
66#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, TypeFingerprint)]
67pub enum BlobFormatV53 {
68 Uncompressed,
69 ChunkedZstd { uncompressed_size: u64, chunk_size: u64, compressed_offsets: Vec<u64> },
70 ChunkedLz4 { uncompressed_size: u64, chunk_size: u64, compressed_offsets: Vec<u64> },
71}