use std::sync::{
atomic::{AtomicBool, Ordering},
RwLock, RwLockReadGuard,
};
use crate::{emulation::EmulationProcess, Error, Result};
pub struct ProcessCell {
initialized: AtomicBool,
process: RwLock<Option<EmulationProcess>>,
label: &'static str,
}
impl ProcessCell {
#[must_use]
pub fn new(label: &'static str) -> Self {
Self {
initialized: AtomicBool::new(false),
process: RwLock::new(None),
label,
}
}
pub fn ensure_initialized<F, P>(
&self,
init_fn: F,
post_init: P,
) -> Result<RwLockReadGuard<'_, Option<EmulationProcess>>>
where
F: FnOnce() -> Option<EmulationProcess>,
P: FnOnce(&EmulationProcess),
{
if !self.initialized.load(Ordering::Acquire) {
let mut guard = self
.process
.write()
.map_err(|e| Error::LockError(format!("{} process write lock: {e}", self.label)))?;
if !self.initialized.load(Ordering::Relaxed) {
let process = init_fn();
if let Some(ref proc) = process {
post_init(proc);
}
*guard = process;
self.initialized.store(true, Ordering::Release);
}
}
self.process
.read()
.map_err(|e| Error::LockError(format!("{} process read lock: {e}", self.label)))
}
#[must_use]
pub fn is_initialized(&self) -> bool {
self.initialized.load(Ordering::Acquire)
}
pub fn take(&self) -> Result<Option<EmulationProcess>> {
let mut guard = self
.process
.write()
.map_err(|e| Error::LockError(format!("{} process write lock: {e}", self.label)))?;
Ok(guard.take())
}
pub fn clear(&self) -> Result<()> {
let mut guard = self
.process
.write()
.map_err(|e| Error::LockError(format!("{} process write lock: {e}", self.label)))?;
*guard = None;
Ok(())
}
}