Skip to main content

sim_lib_journal/
entry.rs

1use sha2::{Digest, Sha256};
2use sim_kernel::{ContentId, Symbol};
3
4/// One immutable journal fact. Kinds and payload interpretation remain open.
5#[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}