1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
extern crate alloc;
use alloc::string::String;
use alloc::vec::Vec;
use super::page::{BlockDot, Page};
use super::{PARAGRAPH, TABLE};
/// One rendered block under the read-side conjunction rule: a block renders
/// as content only when every pair the content needs has arrived, and every
/// other cross-pair state is *classified*, never fabricated. This is
/// candidate answer (a) from the stage-A scoping (caller discipline, no new
/// type), and the coherence scripts test whether it suffices.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Rendered {
/// Kind reads `paragraph` and the paragraph content has arrived.
Paragraph { block: BlockDot, text: String },
/// Kind reads `table` and the table content has arrived.
Table { block: BlockDot, rows: usize },
/// Concurrent kind writes survive as siblings: the conflict is surfaced
/// whole, and which to display is the caller's policy (the kairotic tag
/// is the designed discriminator, horizons axis 8).
MultiKind {
block: BlockDot,
kinds: Vec<&'static str>,
},
/// Fields arrived but the selected kind's content map holds nothing for
/// this block (or the kind register itself is empty): render withholds
/// rather than fabricating. The recorded limit rides here: canonical
/// form drops bottom stores, so a *genuinely empty* block has no
/// content-map key and classifies exactly like an undelivered one;
/// absence cannot say "empty", the recipe's fourth hurt (pinned by
/// `test_empty_block_is_ambiguous_with_undelivered_content`).
KindPending { block: BlockDot },
/// Order arrived ahead of the field pair: a visible block dot with no
/// fields at all, the ghost the naive render shows as a blank block.
Ghost { block: BlockDot },
}
impl Page {
/// The conjunction render beside its deterministic cost: the classified
/// block list and the number of cross-pair map lookups it performed
/// (fields get, kind register read, and one content-map get per selected
/// kind), the per-render counter the measurement report records.
#[must_use]
pub fn render_counted(&self) -> (Vec<Rendered>, usize) {
let mut rendered = Vec::new();
let mut lookups = 0usize;
for block in self.block_order() {
lookups += 1; // fields map get
if !self.fields_present(block) {
rendered.push(Rendered::Ghost { block });
continue;
}
lookups += 1; // kind register read
let kinds = self.kinds(block);
match kinds.as_slice() {
[] => rendered.push(Rendered::KindPending { block }),
[kind] => {
lookups += 1; // the selected kind's content-map get
rendered.push(self.render_kind(block, kind));
}
_ => rendered.push(Rendered::MultiKind { block, kinds }),
}
}
(rendered, lookups)
}
/// The conjunction render alone.
#[must_use]
pub fn render(&self) -> Vec<Rendered> {
self.render_counted().0
}
/// Renders a single-kind block: content when the kind's pair has arrived,
/// [`Rendered::KindPending`] when it has not (or the tag names a kind
/// this recipe has no map for).
fn render_kind(&self, block: BlockDot, kind: &str) -> Rendered {
if kind == PARAGRAPH && self.para_present(block) {
return Rendered::Paragraph {
block,
text: self.para_text(block),
};
}
if kind == TABLE && self.table_present(block) {
return Rendered::Table {
block,
rows: self.table_rows(block),
};
}
Rendered::KindPending { block }
}
/// The naive render's anomaly count: how many order-visible blocks the
/// conjunction rule had to classify as [`Rendered::Ghost`] or
/// [`Rendered::KindPending`] (states a render without the rule would
/// fabricate as blank blocks). Zero on a quiesced page.
#[must_use]
pub fn anomalous_blocks(&self) -> usize {
self.render()
.iter()
.filter(|entry| matches!(entry, Rendered::Ghost { .. } | Rendered::KindPending { .. }))
.count()
}
}