Skip to main content

agentic_reality/format/
sections.rs

1//! Section types and section table for .areal format.
2
3use crate::types::error::{RealityError, RealityResult};
4
5/// Section type identifiers.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[repr(u16)]
8pub enum SectionType {
9    Deployment = 0x0001,
10    Environment = 0x0002,
11    Resource = 0x0003,
12    Reality = 0x0004,
13    Topology = 0x0005,
14    Temporal = 0x0006,
15    Stakes = 0x0007,
16    Coherence = 0x0008,
17    Indexes = 0x0009,
18}
19
20impl SectionType {
21    pub fn from_u16(v: u16) -> RealityResult<Self> {
22        match v {
23            0x0001 => Ok(Self::Deployment),
24            0x0002 => Ok(Self::Environment),
25            0x0003 => Ok(Self::Resource),
26            0x0004 => Ok(Self::Reality),
27            0x0005 => Ok(Self::Topology),
28            0x0006 => Ok(Self::Temporal),
29            0x0007 => Ok(Self::Stakes),
30            0x0008 => Ok(Self::Coherence),
31            0x0009 => Ok(Self::Indexes),
32            _ => Err(RealityError::InvalidFormat(format!(
33                "unknown section type: 0x{:04X}",
34                v
35            ))),
36        }
37    }
38}
39
40/// Entry in the section table.
41#[derive(Debug, Clone)]
42pub struct SectionEntry {
43    pub section_type: SectionType,
44    pub flags: u16,
45    pub offset: u64,
46    pub length: u64,
47    pub uncompressed_length: u64,
48    pub checksum: [u8; 8],
49}
50
51/// Size of a section table entry in bytes.
52pub const SECTION_ENTRY_SIZE: usize = 2 + 2 + 8 + 8 + 8 + 8; // 36 bytes
53
54impl SectionEntry {
55    pub fn write_to(&self, buf: &mut Vec<u8>) {
56        buf.extend_from_slice(&(self.section_type as u16).to_le_bytes());
57        buf.extend_from_slice(&self.flags.to_le_bytes());
58        buf.extend_from_slice(&self.offset.to_le_bytes());
59        buf.extend_from_slice(&self.length.to_le_bytes());
60        buf.extend_from_slice(&self.uncompressed_length.to_le_bytes());
61        buf.extend_from_slice(&self.checksum);
62    }
63
64    pub fn read_from(data: &[u8]) -> RealityResult<Self> {
65        if data.len() < SECTION_ENTRY_SIZE {
66            return Err(RealityError::InvalidFormat(
67                "section entry too short".into(),
68            ));
69        }
70        let section_type = SectionType::from_u16(u16::from_le_bytes(
71            data[0..2]
72                .try_into()
73                .map_err(|_| RealityError::InvalidFormat("section_type".into()))?,
74        ))?;
75        let flags = u16::from_le_bytes(
76            data[2..4]
77                .try_into()
78                .map_err(|_| RealityError::InvalidFormat("flags".into()))?,
79        );
80        let offset = u64::from_le_bytes(
81            data[4..12]
82                .try_into()
83                .map_err(|_| RealityError::InvalidFormat("offset".into()))?,
84        );
85        let length = u64::from_le_bytes(
86            data[12..20]
87                .try_into()
88                .map_err(|_| RealityError::InvalidFormat("length".into()))?,
89        );
90        let uncompressed_length = u64::from_le_bytes(
91            data[20..28]
92                .try_into()
93                .map_err(|_| RealityError::InvalidFormat("uncompressed_length".into()))?,
94        );
95        let checksum: [u8; 8] = data[28..36]
96            .try_into()
97            .map_err(|_| RealityError::InvalidFormat("checksum".into()))?;
98
99        Ok(Self {
100            section_type,
101            flags,
102            offset,
103            length,
104            uncompressed_length,
105            checksum,
106        })
107    }
108}