macroonz_compiler/render/types.rs
1//! The render home's declarations: the ceiling one rendered unit's bytes stand under, one materialized unit, the whole rendering, the sink a renderer writes into, and how rendering says no.
2//!
3//! Declarations only.
4//! Every road that reaches a private field lives in `type_guard.rs`, this file's own child, which is what makes the digest structural: it is taken there over the tree's own canonical bytes, and no caller supplies one.
5
6use crate::bounded::NonEmpty;
7use crate::identity::{self, Identity, OwnerIdentity, Profile};
8use crate::kind::{Kind, Role};
9use crate::origin::OriginTrail;
10use crate::plan::{MEMBERSHIP_LIMIT, Plan};
11use crate::token::{
12 CAPTURED_TOKEN_LIMIT, GeneratedTree, TEXT_SOURCE_BYTE_LIMIT, TOKEN_PATH_DEPTH_LIMIT,
13};
14
15#[path = "type_guard.rs"]
16mod guard;
17
18const CAPTURED_TOKENS_PER_PATH_LEVEL: usize = CAPTURED_TOKEN_LIMIT
19 .checked_div(TOKEN_PATH_DEPTH_LIMIT)
20 .expect("the nonzero token-path depth divides the captured-token magnitude");
21
22/// Bytes one rendered unit may carry.
23///
24/// Derived from the complete callable source magnitude and per-level token magnitude, amortized across the declared nesting depth.
25/// The limit applies to canonical output bytes independently of which capture road supplied the declaration.
26///
27/// A renderer that would emit past this refuses rather than materializing part of a unit.
28pub const RENDERED_BYTE_LIMIT: usize = TEXT_SOURCE_BYTE_LIMIT * CAPTURED_TOKENS_PER_PATH_LEVEL;
29
30/// One unit a renderer actually materialized.
31///
32/// Its seat and every fact that seat's planned member states are carried, so a proof can rebuild a membership out of a rendering and compare it against the declared one; the tree, the identity, and the digest are the rendering's own.
33///
34/// # Nonclaims
35///
36/// The Rust source text is not a member of the unit.
37/// It is [`GeneratedTree::inspected`](crate::token::GeneratedTree::inspected) — a projection of the tree, for a person.
38#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct RenderedUnit<R: Role> {
40 role: R,
41 identity: Identity<identity::RenderedUnit>,
42 semantic_key: Identity<identity::GeneratedUnit>,
43 profile: Profile,
44 origin: OriginTrail,
45 address: Option<OwnerIdentity>,
46 tree: GeneratedTree,
47 digest: Identity<identity::OutputBytes>,
48}
49
50/// Everything one renderer produced for one plan.
51///
52/// Structurally non-empty: a rendering that materialized nothing is not a rendering, and no plan can ever close over one.
53/// Bounded by the magnitude a plan declares its membership inside, because a rendering wider than any plan could declare has no plan to close over.
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct RenderedProjection<R: Role> {
56 units: NonEmpty<RenderedUnit<R>, MEMBERSHIP_LIMIT>,
57}
58
59/// The value a renderer writes its units into.
60///
61/// It holds the plan, so a renderer names a seat and hands over tokens: everything else one unit carries is that seat's planned member, read here.
62/// It holds no proof and makes none — a seat left unfilled and a seat filled twice are written into it as freely as an honest rendering, because those are disagreements between a rendering and a plan and the proof that compares the two is what settles them.
63pub struct Output<'plan, K: Kind> {
64 plan: &'plan Plan<K>,
65 units: Vec<RenderedUnit<K::Role>>,
66}
67
68/// How rendering says no.
69///
70/// One refusal, at the first thing that goes wrong: a unit that cannot be materialized is not a unit, and the units after it were never written.
71/// Three rows name a declared magnitude and the two counts that passed it; the other two say a rendering and a plan's seats do not line up at all.
72#[must_use = "a rendering refusal names the seat or the magnitude the renderer would have passed"]
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
74pub enum RenderError {
75 /// The renderer wrote no unit at all.
76 NothingRendered,
77 /// A unit was written under a seat this plan declares no member for.
78 ///
79 /// Refused where it is written rather than where a proof would notice it, because a unit answers to its member's semantic key and a seat with no member offers none.
80 SeatUnplanned {
81 /// The seat's declared name.
82 role: &'static str,
83 },
84 /// One unit's canonical bytes pass the declared magnitude.
85 BytesUnbounded {
86 /// The seat the unit was written under, by its declared name.
87 role: &'static str,
88 /// The declared bound.
89 bound: usize,
90 /// The observed count.
91 observed: usize,
92 },
93 /// The rendering carries more units than the declared magnitude admits.
94 UnitsUnbounded {
95 /// The declared bound.
96 bound: usize,
97 /// The observed count.
98 observed: usize,
99 },
100 /// A generated tree passed the declared per-level magnitude while a unit was being composed.
101 ///
102 /// The one overflow a renderer meets: the composition helpers and the tree assembler are what it builds with, and they are the only roads it takes that bound anything.
103 TokensUnbounded {
104 /// The declared bound.
105 bound: usize,
106 /// The observed count.
107 observed: usize,
108 },
109}