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 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}