Skip to main content

urna_format/layout/
section_entry.rs

1//! section table entry (32 bytes per entry, fixed layout).
2//!
3//! `offset` is 64-byte aligned (see `SECTION_ALIGNMENT`). `size` is the
4//! length of the actual payload, NOT including the trailing padding.
5//! `encoding` declares the on-disk payload format; v1 supports raw,
6//! zstd, float16 and int8.
7
8use crate::error::UrnaError;
9use sha2::{Digest, Sha256};
10
11use super::SECTION_ENCODING_RAW;
12
13// `Pod` + `Zeroable` are derived, not asserted: the derive fails to
14// compile if the struct ever gains padding or a field that is not valid
15// for every bit pattern, which is exactly the invariant the on-disk
16// byte view below relies on. No `unsafe` in this file.
17#[repr(C)]
18#[derive(Clone, Copy, Debug, PartialEq, bytemuck::Pod, bytemuck::Zeroable)]
19pub struct SectionEntry {
20    pub section_id: u32,
21    pub encoding: u32,
22    pub offset: u64,
23    pub size: u64,
24    pub checksum: [u8; 8],
25}
26
27impl SectionEntry {
28    pub fn new(section_id: u32, offset: u64, size: u64) -> Self {
29        Self {
30            section_id,
31            encoding: SECTION_ENCODING_RAW,
32            offset,
33            size,
34            checksum: [0; 8],
35        }
36    }
37
38    /// The exact on-disk bytes of this record (little-endian host only,
39    /// which is every supported target; see `layout::tests`).
40    pub fn as_bytes(&self) -> &[u8] {
41        bytemuck::bytes_of(self)
42    }
43
44    /// Mutable view over the on-disk bytes; `from_bytes`-style readers copy
45    /// a slice in here. Sound for any content because every field accepts
46    /// every bit pattern (`Pod`).
47    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
48        bytemuck::bytes_of_mut(self)
49    }
50
51    pub fn compute_checksum(&mut self, data: &[u8]) {
52        let hash = Sha256::digest(data);
53        self.checksum.copy_from_slice(&hash[..8]);
54    }
55
56    pub fn validate_checksum(&self, data: &[u8]) -> crate::Result<()> {
57        let hash = Sha256::digest(data);
58        if hash[..8] != self.checksum[..] {
59            return Err(UrnaError::SectionChecksumMismatch(self.section_id));
60        }
61        Ok(())
62    }
63}