concinnity_core/blob/encode.rs
1// The blob encode half. Writing the bytes out is the caller's job: only
2// concinnity-cook packs blobs, and it already owns the packing policy (payload
3// distribution across overflow blobs, the size ceiling) and the output paths.
4
5use alloc::vec::Vec;
6
7use crate::blob::HEADER_SIZE;
8use crate::blob::error::BlobError;
9use crate::blob::kind::BlobKind;
10
11/// Encode a blob image: the 16-byte header, the postcard-serialized metadata
12/// block, then the raw payload section.
13///
14/// The header's magic comes from `K`, so the bytes declare which kind of
15/// container they are.
16///
17/// `validity` is the token stamped into the header and required to match on
18/// parse. What it means belongs to the kind: for the cooked world's
19/// [`BlobMeta`](crate::blob::BlobMeta) it is a schema version, and runtime
20/// callers pass `concinnity_core::SCHEMA_VERSION`.
21pub fn encode_cnb<K: BlobKind>(
22 validity: u32,
23 meta: &K,
24 payload: &[u8],
25) -> Result<Vec<u8>, BlobError> {
26 let mut data = encode_cnb_prefix(validity, meta)?;
27 data.reserve(payload.len());
28 data.extend_from_slice(payload);
29 Ok(data)
30}
31
32/// Everything an image carries before its payload section: the 16-byte header
33/// and the metadata block.
34///
35/// For a writer that streams its payload rather than holding it in memory. A
36/// build cache segment is the case that needs it: its payload can run to
37/// hundreds of megabytes, most of them copied from the segment it replaces, so
38/// the bytes go to the file as they are produced and only this prefix is built
39/// as a value.
40pub fn encode_cnb_prefix<K: BlobKind>(validity: u32, meta: &K) -> Result<Vec<u8>, BlobError> {
41 let meta_bytes: Vec<u8> = postcard::to_allocvec(meta).map_err(|_| BlobError::Encode)?;
42
43 let mut data = Vec::with_capacity(HEADER_SIZE + meta_bytes.len());
44 data.extend_from_slice(&K::MAGIC);
45 data.extend_from_slice(&validity.to_le_bytes());
46 data.extend_from_slice(&(meta_bytes.len() as u64).to_le_bytes());
47 data.extend_from_slice(&meta_bytes);
48 Ok(data)
49}