atomic_ops/
recover.rs

1use std::path::Path;
2
3use crate::{
4    error::{OpsError, OpsResult},
5    operation::{LoaderFn, Ops},
6    process::{BoxedProc, ProcStatus, BOXED_PROC_SIZE},
7};
8
9pub struct OpsRecovery {
10    loaders: [Option<LoaderFn>; 255],
11}
12
13const ARRAY_REPEAT_VALUE: Option<LoaderFn> = None;
14impl Default for OpsRecovery {
15    fn default() -> Self {
16        Self {
17            loaders: [ARRAY_REPEAT_VALUE; 255],
18        }
19    }
20}
21impl OpsRecovery {
22    pub fn add_loader(&mut self, index: u8, loader: LoaderFn) {
23        self.loaders[index as usize] = Some(loader);
24    }
25
26    pub fn add_loaders(&mut self, loaders: Vec<(u8, LoaderFn)>) {
27        for (index, loader) in loaders {
28            self.loaders[index as usize] = Some(loader);
29        }
30    }
31
32    pub fn recover(&self, path: &Path) -> OpsResult<Ops> {
33        let mut bytes = std::fs::read(path)?;
34
35        let mut boxed_ops = Vec::new();
36        let mut total_length: usize = 0;
37        loop {
38            if bytes.len() < BOXED_PROC_SIZE {
39                break;
40            }
41            let length = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as usize;
42            let ops_id = bytes[4];
43            let status: ProcStatus = bytes[5].try_into()?;
44            bytes = bytes.split_off(6);
45            println!("Read leangth {length}, ops_id={ops_id}, status={status:?}");
46
47            // exit if it's incorrect fiish
48            if bytes.len() < length {
49                break;
50            }
51            let Some(loader) = &self.loaders[ops_id as usize] else {
52                return Err(OpsError::Unknown);
53            };
54
55            total_length += BOXED_PROC_SIZE + length;
56            let boxed =
57                BoxedProc::new_with_offset(ops_id, loader(&bytes[..length])?, status, total_length);
58            boxed_ops.push(boxed);
59            bytes = bytes.split_off(length);
60        }
61        Ops::new(path, boxed_ops)
62    }
63}