atomic-ops 0.1.1

Performs atomic operations in the filesystem
Documentation
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:?}");

            // exit if it's incorrect fiish
            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)
    }
}