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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
extern crate alloc;
use crate::metis::{Anchor, DotFun, DotMap, DotSet, DotStore, Locus, Rhapsody};
use super::page::{BlockDot, Field, Page};
impl Page {
/// Creates a block at the visual slot after `after` (`None` at the page
/// start), writing its kind and title fields, and returns its identity:
/// the order-pair dot. One "create" is three writes across two pairs
/// (one order weave, two field registers), which is exactly the
/// cross-pair atomicity seam the coherence scripts pry at.
pub fn create_block(
&mut self,
kind: &'static str,
title: &'static str,
after: Option<BlockDot>,
) -> BlockDot {
let anchor = self
.order
.state()
.store()
.anchor_for_visual_insert(after.map(Into::into));
// Observe the top sibling's rank so the mint places this block at the
// chosen visual slot (the editor's weave_at_seam discipline).
if let Some(top_child) = self.order.state().store().children_of(anchor).next()
&& let Some(locus) = self.order.state().store().locus(top_child)
{
self.clock.observe(locus.rank);
}
let rank = self.clock.now(0u16);
let (block, _) = self.order.compose(|assigned| {
let mut rhapsody = Rhapsody::new();
let _ = rhapsody.weave(assigned, Locus { anchor, rank });
(rhapsody, DotSet::new())
});
self.set_kind(block, kind);
self.set_title(block, title);
block
}
/// Writes the block's kind register, superseding the kind dots this
/// replica has observed (concurrent kind writes therefore surface as
/// siblings, never resolve).
pub fn set_kind(&mut self, block: BlockDot, kind: &'static str) {
let _ = self.fields.compose_super(
|assigned| {
DotMap::singleton(
block,
DotMap::singleton(Field::Kind, DotFun::singleton(assigned, kind)),
)
},
|held| {
held.get(&block)
.and_then(|fields| fields.get(&Field::Kind))
.map(DotFun::observed)
.unwrap_or_default()
},
);
}
/// Writes the block's title register, superseding the observed title dots.
pub fn set_title(&mut self, block: BlockDot, title: &'static str) {
let _ = self.fields.compose_super(
|assigned| {
DotMap::singleton(
block,
DotMap::singleton(Field::Title, DotFun::singleton(assigned, title)),
)
},
|held| {
held.get(&block)
.and_then(|fields| fields.get(&Field::Title))
.map(DotFun::observed)
.unwrap_or_default()
},
);
}
/// Types `ch` into `block`'s paragraph sequence, anchored after `after`
/// (`None` at the paragraph origin), and returns the char's para-pair
/// dot. The nested weave mints from the *paragraph pair's* context; the
/// block dot is only the map key.
pub fn type_into(
&mut self,
block: BlockDot,
ch: char,
after: Option<crate::metis::Dot>,
) -> crate::metis::Dot {
let anchor = after.map_or(Anchor::Origin, |dot| Anchor::After(dot.into()));
let rank = self.clock.now(0u16);
let (dot, _) = self.para.compose(|assigned| {
let mut rhapsody = Rhapsody::new();
let _ = rhapsody.weave(assigned, Locus { anchor, rank });
(DotMap::singleton(block, rhapsody), DotSet::new())
});
let _ = self.chars.insert(dot, ch);
dot
}
/// Writes the cell register at `(block, row)`, superseding the observed
/// cell dots.
pub fn set_cell(&mut self, block: BlockDot, row: u32, value: &'static str) {
let _ = self.table.compose_super(
|assigned| {
DotMap::singleton(
block,
DotMap::singleton(row, DotFun::singleton(assigned, value)),
)
},
|held| {
held.get(&block)
.and_then(|rows| rows.get(&row))
.map(DotFun::observed)
.unwrap_or_default()
},
);
}
/// Deletes the block from the *order pair only*: the natural hand-roll,
/// which leaves every content pair holding the tombstoned block's state
/// (the no-canonical-drop pain point the kind scripts record).
pub fn delete_block_order_only(&mut self, block: BlockDot) {
let mut superseded = DotSet::new();
let _ = superseded.insert(block);
let _ = self.order.retract(superseded);
}
/// Retracts every observed paragraph char under `block`: the cross-pair
/// half of an honest delete or kind reassignment, a *separate* delta on a
/// separate pair (no atomicity with the order or field writes exists,
/// which is the window the coherence scripts measure).
pub fn retract_para_content(&mut self, block: BlockDot) {
let observed = self
.para
.state()
.store()
.get(&block)
.map(|rhapsody| {
let mut set = DotSet::new();
for dot in rhapsody.dots() {
let _ = set.insert(dot);
}
set
})
.unwrap_or_default();
let _ = self.para.retract(observed);
}
}