use std::path::Path;
use crate::{
error::{OpsError, OpsResult},
operation::{LoaderFn, Ops},
process::{BoxedProc, ProcStatus, BOXED_PROC_SIZE},
};
pub struct OpsRecovery {
loaders: [Option<LoaderFn>; 255],
}
const ARRAY_REPEAT_VALUE: Option<LoaderFn> = None;
impl Default for OpsRecovery {
fn default() -> Self {
Self {
loaders: [ARRAY_REPEAT_VALUE; 255],
}
}
}
impl OpsRecovery {
pub fn add_loader(&mut self, index: u8, loader: LoaderFn) {
self.loaders[index as usize] = Some(loader);
}
pub fn add_loaders(&mut self, loaders: Vec<(u8, LoaderFn)>) {
for (index, loader) in loaders {
self.loaders[index as usize] = Some(loader);
}
}
pub fn recover(&self, path: &Path) -> OpsResult<Ops> {
let mut bytes = std::fs::read(path)?;
let mut boxed_ops = Vec::new();
let mut total_length: usize = 0;
loop {
if bytes.len() < BOXED_PROC_SIZE {
break;
}
let length = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as usize;
let ops_id = bytes[4];
let status: ProcStatus = bytes[5].try_into()?;
bytes = bytes.split_off(6);
println!("Read leangth {length}, ops_id={ops_id}, status={status:?}");
if bytes.len() < length {
break;
}
let Some(loader) = &self.loaders[ops_id as usize] else {
return Err(OpsError::Unknown);
};
total_length += BOXED_PROC_SIZE + length;
let boxed =
BoxedProc::new_with_offset(ops_id, loader(&bytes[..length])?, status, total_length);
boxed_ops.push(boxed);
bytes = bytes.split_off(length);
}
Ops::new(path, boxed_ops)
}
}