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
|
//! For tests: writing to documents the way the node does, one change at a time, so
//! that tests don't depend on how the engine groups writes into changes.
use super::{Document, Transaction};
/// The writes `f` makes to `doc`, as one change; what `f` returns.
pub(crate) fn change<T>(doc: &mut Document, f: impl FnOnce(&mut Transaction<'_>) -> T) -> T {
let mut transaction = doc.transaction();
let out = f(&mut transaction);
transaction.commit();
out
}
/// The writes `f` makes to `doc`, as one change if it succeeds, dropped if not; what
/// `f` returns. Committed at time 0: the same writes make the same change.
pub(crate) fn try_change<T, E>(
doc: &mut Document,
f: impl FnOnce(&mut Transaction<'_>) -> Result<T, E>,
) -> Result<T, E> {
let mut transaction = doc.transaction();
let out = f(&mut transaction);
match &out {
Ok(_) => {
transaction.commit_with(automerge::transaction::CommitOptions::default().with_time(0));
}
Err(_) => {
transaction.rollback();
}
}
out
}
/// `raw` (an uncompressed change chunk, as `Change::raw_bytes` gives one) with an author
/// footer appended to its extra bytes, its checksum made right again: what no honest
/// node sends for a change that isn't its actor's first (`changes::misplaced_author`).
pub(crate) fn with_author_footer(raw: &[u8], author: &[u8]) -> Vec<u8> {
use sha2::{Digest, Sha256};
fn leb(mut n: usize, out: &mut Vec<u8>) {
loop {
let byte = (n & 0x7f) as u8;
n >>= 7;
if n == 0 {
out.push(byte);
return;
}
out.push(byte | 0x80);
}
}
assert_eq!(raw[8], 1, "an uncompressed change chunk");
let (mut length, mut read, mut shift) = (0usize, 0, 0);
loop {
let byte = raw[9 + read];
length |= usize::from(byte & 0x7f) << shift;
read += 1;
if byte & 0x80 == 0 {
break;
}
shift += 7;
}
let mut body = raw[9 + read..9 + read + length].to_vec();
body.push(1);
leb(author.len(), &mut body);
body.extend_from_slice(author);
let mut header = Vec::new();
leb(body.len(), &mut header);
let mut summed = vec![1u8];
summed.extend(&header);
summed.extend(&body);
let sum = Sha256::digest(&summed);
let mut out = raw[..4].to_vec();
out.extend(&sum[..4]);
out.push(1);
out.extend(header);
out.extend(body);
out
}
|