pub mod constants;
pub mod file;
use crate::error::{OpsError, OpsResult};
use std::cell::RefCell;
#[derive(Clone, Copy, Debug)]
pub enum ProcStatus {
INIT,
PREPARED,
RAN,
CLEAN,
REVERTED,
}
impl From<ProcStatus> for u8 {
fn from(value: ProcStatus) -> Self {
match value {
ProcStatus::INIT => 0,
ProcStatus::PREPARED => 1,
ProcStatus::RAN => 2,
ProcStatus::CLEAN => 3,
ProcStatus::REVERTED => 4,
}
}
}
impl TryFrom<u8> for ProcStatus {
type Error = OpsError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(ProcStatus::INIT),
1 => Ok(ProcStatus::PREPARED),
2 => Ok(ProcStatus::RAN),
3 => Ok(ProcStatus::CLEAN),
4 => Ok(ProcStatus::REVERTED),
_ => Err(OpsError::SerializeFailed),
}
}
}
pub trait Process {
fn prepare(&self) -> OpsResult<()>;
fn run(&self) -> OpsResult<()>;
fn clean(&self) -> OpsResult<()>;
fn revert_prepare(&self) -> OpsResult<()>;
fn revert_run(&self) -> OpsResult<()>;
fn as_bytes(&self) -> &[u8];
fn id() -> u8
where
Self: Sized;
}
pub struct BoxedProc {
id: u8,
offset: usize,
status: RefCell<ProcStatus>,
process: Box<dyn Process>,
}
pub const STATUS_SHIFT: usize = 5;
pub const BOXED_PROC_SIZE: usize = 6; impl BoxedProc {
pub fn new(id: u8, process: Box<dyn Process>) -> Self {
Self {
id,
offset: 0,
status: RefCell::new(ProcStatus::INIT),
process,
}
}
pub fn new_with_offset(
id: u8,
process: Box<dyn Process>,
status: ProcStatus,
offset: usize,
) -> Self {
Self {
id,
offset,
status: RefCell::new(status),
process,
}
}
#[inline]
pub fn prepare(&self) -> OpsResult<()> {
println!("Prepare {}", self.id);
let mut borrow = self
.status
.try_borrow_mut()
.map_err(|_| OpsError::BorrowingStatusFailed)?;
self.process.prepare()?;
*borrow = ProcStatus::PREPARED;
Ok(())
}
#[inline]
pub fn run(&self) -> OpsResult<()> {
println!("Run {}", self.id);
let mut borrow = self
.status
.try_borrow_mut()
.map_err(|_| OpsError::BorrowingStatusFailed)?;
self.process.run()?;
*borrow = ProcStatus::RAN;
Ok(())
}
#[inline]
pub fn clean(&self) -> OpsResult<()> {
println!("Clean {}", self.id);
let mut borrow = self
.status
.try_borrow_mut()
.map_err(|_| OpsError::BorrowingStatusFailed)?;
self.process.clean()?;
*borrow = ProcStatus::CLEAN;
Ok(())
}
#[inline]
pub fn revert_prepare(&self) -> OpsResult<()> {
println!("Revert PREPARE {}", self.id);
self.process.revert_prepare()
}
#[inline]
pub fn revert_run(&self) -> OpsResult<()> {
println!("Revert RUN {}", self.id);
self.process.revert_run()
}
#[inline]
pub fn status(&self) -> ProcStatus {
*self.status.borrow()
}
#[inline]
pub fn offcet(&self) -> usize {
self.offset
}
#[inline]
pub fn id(&self) -> u8 {
self.id
}
#[inline]
pub fn set_offset(&mut self, offset: usize) {
self.offset = offset;
}
#[inline]
pub fn encode(&self) -> Vec<u8> {
let process_bytes = self.process.as_bytes();
let length = process_bytes.len();
let status: u8 = self.status().into();
let mut bytes = Vec::with_capacity(length);
bytes.extend_from_slice((length as u32).to_le_bytes().as_slice());
bytes.extend_from_slice(&[self.id]);
bytes.extend_from_slice(&[status]);
bytes.extend_from_slice(process_bytes);
bytes
}
#[inline]
pub fn print(&self) {
println!("BoxedProc: {}, {:?}", self.id, self.status)
}
}