use std::path::Path;
use std::sync::Arc;
use parking_lot::Mutex;
use crate::common::is_alive_lock::IsAliveLock;
use crate::common::universal_io::{
Flusher, OpenOptions, TypedStorage, UioResult, UniversalReadFs, UniversalWrite,
};
#[derive(Debug)]
pub struct StoredStruct<S, T> {
inner: T,
storage: Arc<Mutex<TypedStorage<S, T>>>,
is_alive_lock: IsAliveLock,
}
impl<S, T> StoredStruct<S, T>
where
T: bytemuck::Pod + Send,
S: UniversalWrite + Send + 'static,
{
pub fn open<Fs: UniversalReadFs<File = S>>(
fs: &Fs,
path: impl AsRef<Path>,
options: OpenOptions,
extra: Fs::OpenExtra,
) -> UioResult<Self> {
let storage = TypedStorage::<S, T>::open(fs, path, options, extra)?;
let inner = storage.read_whole()?[0];
Ok(Self {
inner,
storage: Arc::new(Mutex::new(storage)),
is_alive_lock: IsAliveLock::new(),
})
}
pub fn flusher(&self) -> Flusher {
let state = self.inner; let storage = Arc::downgrade(&self.storage);
let is_alive = self.is_alive_lock.handle();
Box::new(move || {
let (Some(_is_alive), Some(storage)) = (is_alive.lock_if_alive(), storage.upgrade())
else {
return Ok(());
};
let mut storage = storage.lock();
storage.write(0, &[state])?;
storage.flusher()()?;
Ok(())
})
}
}
impl<S, T> std::ops::Deref for StoredStruct<S, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<S, T> std::ops::DerefMut for StoredStruct<S, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}