umsh_journal_store/
record.rs1pub const PAGE_SIZE: u32 = 4096;
11
12pub fn generation_is_newer(candidate: u32, current: u32) -> bool {
15 candidate != current && candidate.wrapping_sub(current) < (1 << 31)
16}
17
18#[allow(async_fn_in_trait)]
20pub trait RecordWriter {
21 type Error;
22
23 async fn write_record(&mut self, address: u32, bytes: &[u8]) -> Result<(), Self::Error>;
24}
25
26#[allow(async_fn_in_trait)]
27pub trait PageEraser {
28 type Error;
29
30 async fn erase_page(&mut self, start: u32, end: u32) -> Result<(), Self::Error>;
31}
32
33pub trait RecordReader {
42 type Error;
43
44 fn read_record(&mut self, address: u32, bytes: &mut [u8]) -> Result<(), Self::Error>;
45}
46
47#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48pub enum CommitError<E> {
49 Body(E),
50 Commit(E),
51}
52
53pub async fn write_committed_record<W: RecordWriter, const SLOT: usize>(
61 writer: &mut W,
62 target: u32,
63 bytes: &[u8; SLOT],
64) -> Result<(), CommitError<W::Error>> {
65 let commit_offset = SLOT - 4;
66 writer
67 .write_record(target, &bytes[..commit_offset])
68 .await
69 .map_err(CommitError::Body)?;
70 writer
71 .write_record(target + commit_offset as u32, &[0; 4])
72 .await
73 .map_err(CommitError::Commit)
74}
75
76pub async fn erase_journal_page<E: PageEraser>(eraser: &mut E, page: u32) -> Result<(), E::Error> {
77 eraser.erase_page(page, page + PAGE_SIZE).await
78}
79
80pub fn crc32(bytes: &[u8]) -> u32 {
83 let mut crc = 0xffff_ffffu32;
84 for &byte in bytes {
85 crc ^= u32::from(byte);
86 for _ in 0..8 {
87 crc = (crc >> 1) ^ (0xedb8_8320 & 0u32.wrapping_sub(crc & 1));
88 }
89 }
90 !crc
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn generation_comparison_handles_wraparound() {
99 assert!(generation_is_newer(0, u32::MAX));
100 assert!(!generation_is_newer(u32::MAX, 0));
101 }
102}