Skip to main content

firecloud_core/
chunk.rs

1//! Chunk-related types for content-addressed storage
2
3use serde::{Deserialize, Serialize};
4use std::fmt;
5
6/// A 256-bit BLAKE3 hash identifying a chunk
7#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
8pub struct ChunkHash(pub [u8; 32]);
9
10impl ChunkHash {
11    /// Create from raw bytes
12    pub fn from_bytes(bytes: [u8; 32]) -> Self {
13        Self(bytes)
14    }
15
16    /// Hash data to create a ChunkHash
17    pub fn hash(data: &[u8]) -> Self {
18        let hash = blake3::hash(data);
19        Self(*hash.as_bytes())
20    }
21
22    /// Get as hex string
23    pub fn to_hex(&self) -> String {
24        hex::encode(self.0)
25    }
26
27    /// Parse from hex string
28    pub fn from_hex(s: &str) -> Result<Self, hex::FromHexError> {
29        let bytes = hex::decode(s)?;
30        let arr: [u8; 32] = bytes.try_into().map_err(|_| hex::FromHexError::InvalidStringLength)?;
31        Ok(Self(arr))
32    }
33}
34
35impl fmt::Debug for ChunkHash {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        write!(f, "ChunkHash({})", &self.to_hex()[..16])
38    }
39}
40
41impl fmt::Display for ChunkHash {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        write!(f, "{}", &self.to_hex()[..16])
44    }
45}
46
47/// Unique identifier for a chunk (alias for ChunkHash in content-addressed storage)
48pub type ChunkId = ChunkHash;
49
50/// Metadata about a stored chunk
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct ChunkMetadata {
53    /// Content hash (also serves as ID)
54    pub hash: ChunkHash,
55    /// Size in bytes (after compression, before encryption)
56    pub size: u64,
57    /// Original (uncompressed) size
58    pub original_size: u64,
59    /// Compression algorithm used
60    pub compression: CompressionType,
61    /// Whether this chunk is encrypted
62    pub encrypted: bool,
63}
64
65/// Compression algorithms supported
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
67pub enum CompressionType {
68    None,
69    Zstd,
70    Lz4,
71}
72
73/// A chunk of file data
74#[derive(Debug, Clone)]
75pub struct Chunk {
76    /// Metadata about this chunk
77    pub metadata: ChunkMetadata,
78    /// The actual data (compressed and/or encrypted)
79    pub data: bytes::Bytes,
80}
81
82impl Chunk {
83    /// Create a new chunk from raw data
84    pub fn new(data: bytes::Bytes, original_size: u64, compression: CompressionType) -> Self {
85        let hash = ChunkHash::hash(&data);
86        Self {
87            metadata: ChunkMetadata {
88                hash,
89                size: data.len() as u64,
90                original_size,
91                compression,
92                encrypted: false,
93            },
94            data,
95        }
96    }
97
98    /// Get the chunk's content hash
99    pub fn hash(&self) -> &ChunkHash {
100        &self.metadata.hash
101    }
102}