Skip to main content

macroonz_compiler/render/
encode.rs

1//! The canonical bytes one rendering refusal exposes.
2//!
3//! The row's position rides ahead of the material it governs, and the material is framed through the identity home's one framing, so two rows carrying the same counts never encode alike.
4//!
5//! Rendering refusals enumerate no related issues today, so a diagnostic derives no related identity from these bytes.
6//! They remain the refusal's canonical machine projection, independent of the human sentence projected from it.
7//!
8//! A rendered unit has no whole-value encoding here, and the absence is the no-double-entry law: what a unit IS reaches a preimage through its own identity and its digest, both derived over the tree's bytes at full width, and what it ANSWERS TO reaches one through the planned member it reconstructs, which the plan home already spells.
9
10use super::RenderError;
11use crate::identity::encode_bytes;
12
13impl RenderError {
14    /// This refusal's canonical bytes on their own.
15    #[must_use]
16    pub fn canonical_bytes(&self) -> Vec<u8> {
17        let mut bytes = Vec::new();
18        self.encode_into(&mut bytes);
19        bytes
20    }
21
22    /// Appends this refusal's canonical bytes: the row's position in the declared roster, then the typed material that row carries, framed.
23    ///
24    /// Exhaustive over the roster on purpose: a row added to [`RenderError`] stops compiling HERE until somebody says what of it a preimage commits to.
25    pub fn encode_into(&self, into: &mut Vec<u8>) {
26        into.push(self.slot());
27        let mut material = Vec::new();
28        self.material_into(&mut material);
29        encode_bytes(&material, into);
30    }
31
32    /// The typed material one refusal carries.
33    ///
34    /// The two magnitude rows that carry only counts share this spelling and are separated by the row position written ahead of them.
35    fn material_into(&self, into: &mut Vec<u8>) {
36        match self {
37            Self::NothingRendered => {}
38            Self::SeatUnplanned { role } => encode_bytes(role.as_bytes(), into),
39            Self::BytesUnbounded {
40                role,
41                bound,
42                observed,
43            } => {
44                encode_bytes(role.as_bytes(), into);
45                counted_into(*bound, into);
46                counted_into(*observed, into);
47            }
48            Self::UnitsUnbounded { bound, observed }
49            | Self::TokensUnbounded { bound, observed } => {
50                counted_into(*bound, into);
51                counted_into(*observed, into);
52            }
53        }
54    }
55}
56
57/// Appends one count as eight big-endian bytes, saturating where a count outruns that width.
58fn counted_into(value: usize, into: &mut Vec<u8>) {
59    into.extend_from_slice(&u64::try_from(value).unwrap_or(u64::MAX).to_be_bytes());
60}