atomic_ops/process/
mod.rs

1pub mod constants;
2pub mod file;
3
4use crate::error::{OpsError, OpsResult};
5use std::cell::RefCell;
6
7#[derive(Clone, Copy, Debug)]
8pub enum ProcStatus {
9    INIT,
10    PREPARED,
11    RAN,
12    CLEAN,
13    REVERTED,
14}
15
16impl From<ProcStatus> for u8 {
17    fn from(value: ProcStatus) -> Self {
18        match value {
19            ProcStatus::INIT => 0,
20            ProcStatus::PREPARED => 1,
21            ProcStatus::RAN => 2,
22            ProcStatus::CLEAN => 3,
23            ProcStatus::REVERTED => 4,
24        }
25    }
26}
27
28impl TryFrom<u8> for ProcStatus {
29    type Error = OpsError;
30
31    fn try_from(value: u8) -> Result<Self, Self::Error> {
32        match value {
33            0 => Ok(ProcStatus::INIT),
34            1 => Ok(ProcStatus::PREPARED),
35            2 => Ok(ProcStatus::RAN),
36            3 => Ok(ProcStatus::CLEAN),
37            4 => Ok(ProcStatus::REVERTED),
38            _ => Err(OpsError::SerializeFailed),
39        }
40    }
41}
42
43pub trait Process {
44    fn prepare(&self) -> OpsResult<()>;
45    fn run(&self) -> OpsResult<()>;
46    fn clean(&self) -> OpsResult<()>;
47
48    fn revert_prepare(&self) -> OpsResult<()>;
49    fn revert_run(&self) -> OpsResult<()>;
50
51    fn as_bytes(&self) -> &[u8];
52
53    fn id() -> u8
54    where
55        Self: Sized;
56}
57
58pub struct BoxedProc {
59    id: u8,
60    offset: usize,
61    status: RefCell<ProcStatus>,
62    process: Box<dyn Process>,
63}
64
65pub const STATUS_SHIFT: usize = 5;
66pub const BOXED_PROC_SIZE: usize = 6; // length(4) + status(1) + id(1)
67impl BoxedProc {
68    pub fn new(id: u8, process: Box<dyn Process>) -> Self {
69        Self {
70            id,
71            offset: 0,
72            status: RefCell::new(ProcStatus::INIT),
73            process,
74        }
75    }
76
77    pub fn new_with_offset(
78        id: u8,
79        process: Box<dyn Process>,
80        status: ProcStatus,
81        offset: usize,
82    ) -> Self {
83        Self {
84            id,
85            offset,
86            status: RefCell::new(status),
87            process,
88        }
89    }
90
91    #[inline]
92    pub fn prepare(&self) -> OpsResult<()> {
93        println!("Prepare {}", self.id);
94        let mut borrow = self
95            .status
96            .try_borrow_mut()
97            .map_err(|_| OpsError::BorrowingStatusFailed)?;
98        self.process.prepare()?;
99        *borrow = ProcStatus::PREPARED;
100        Ok(())
101    }
102
103    #[inline]
104    pub fn run(&self) -> OpsResult<()> {
105        println!("Run {}", self.id);
106        let mut borrow = self
107            .status
108            .try_borrow_mut()
109            .map_err(|_| OpsError::BorrowingStatusFailed)?;
110        self.process.run()?;
111        *borrow = ProcStatus::RAN;
112        Ok(())
113    }
114
115    #[inline]
116    pub fn clean(&self) -> OpsResult<()> {
117        println!("Clean {}", self.id);
118        let mut borrow = self
119            .status
120            .try_borrow_mut()
121            .map_err(|_| OpsError::BorrowingStatusFailed)?;
122        self.process.clean()?;
123        *borrow = ProcStatus::CLEAN;
124        Ok(())
125    }
126
127    #[inline]
128    pub fn revert_prepare(&self) -> OpsResult<()> {
129        println!("Revert PREPARE {}", self.id);
130        self.process.revert_prepare()
131    }
132
133    #[inline]
134    pub fn revert_run(&self) -> OpsResult<()> {
135        println!("Revert RUN {}", self.id);
136        self.process.revert_run()
137    }
138
139    #[inline]
140    pub fn status(&self) -> ProcStatus {
141        *self.status.borrow()
142    }
143
144    #[inline]
145    pub fn offcet(&self) -> usize {
146        self.offset
147    }
148
149    #[inline]
150    pub fn id(&self) -> u8 {
151        self.id
152    }
153
154    #[inline]
155    pub fn set_offset(&mut self, offset: usize) {
156        self.offset = offset;
157    }
158
159    #[inline]
160    pub fn encode(&self) -> Vec<u8> {
161        let process_bytes = self.process.as_bytes();
162        let length = process_bytes.len();
163        let status: u8 = self.status().into();
164        let mut bytes = Vec::with_capacity(length);
165
166        // max size of file is 4GB
167        bytes.extend_from_slice((length as u32).to_le_bytes().as_slice());
168        bytes.extend_from_slice(&[self.id]);
169        bytes.extend_from_slice(&[status]);
170        bytes.extend_from_slice(process_bytes);
171        bytes
172    }
173
174    #[inline]
175    pub fn print(&self) {
176        println!("BoxedProc: {}, {:?}", self.id, self.status)
177    }
178}