1use sha2::{Digest, Sha256};
2use sim_kernel::{ContentId, Symbol};
3
4#[derive(Clone, Debug, PartialEq, Eq)]
6pub struct JournalEntry {
7 pub id: ContentId,
8 pub sequence: u64,
9 pub previous: Option<ContentId>,
10 pub kind: Symbol,
11 pub payloads: Vec<ContentId>,
12}
13
14impl JournalEntry {
15 pub fn new(
16 sequence: u64,
17 previous: Option<ContentId>,
18 kind: Symbol,
19 payloads: Vec<ContentId>,
20 ) -> Self {
21 let mut value = Self {
22 id: ContentId::from_bytes(Symbol::new("unset"), [0; 32]),
23 sequence,
24 previous,
25 kind,
26 payloads,
27 };
28 value.id = value.canonical_id();
29 value
30 }
31
32 pub(crate) fn canonical_id(&self) -> ContentId {
33 let mut hasher = Sha256::new();
34 hasher.update(b"sim-journal-entry-v1\0");
35 hasher.update(self.sequence.to_be_bytes());
36 encode_optional_id(&mut hasher, self.previous.as_ref());
37 encode_symbol(&mut hasher, &self.kind);
38 hasher.update((self.payloads.len() as u64).to_be_bytes());
39 for id in &self.payloads {
40 encode_id(&mut hasher, id);
41 }
42 ContentId::from_bytes(
43 Symbol::qualified("journal", "sha256-entry-v1"),
44 hasher.finalize().into(),
45 )
46 }
47}
48
49fn encode_optional_id(hasher: &mut Sha256, id: Option<&ContentId>) {
50 match id {
51 Some(id) => {
52 hasher.update([1]);
53 encode_id(hasher, id);
54 }
55 None => {
56 hasher.update([0]);
57 }
58 }
59}
60fn encode_id(hasher: &mut Sha256, id: &ContentId) {
61 encode_symbol(hasher, &id.algorithm);
62 hasher.update(id.bytes);
63}
64fn encode_symbol(hasher: &mut Sha256, symbol: &Symbol) {
65 let text = symbol.as_qualified_str();
66 hasher.update((text.len() as u64).to_be_bytes());
67 hasher.update(text.as_bytes());
68}