use std::sync::{Arc, Condvar, Mutex};
use std::time::Duration;
use crate::backend::Storage;
use crate::error::{Error, Result};
#[derive(Clone)]
pub struct MemStorage(Arc<Inner>);
struct Inner {
data: Mutex<Vec<u8>>,
changed: Condvar,
}
impl MemStorage {
pub fn new(size: u64) -> Self {
assert!(size > 0, "backend: MemStorage size must be positive");
MemStorage(Arc::new(Inner {
data: Mutex::new(vec![0u8; size as usize]),
changed: Condvar::new(),
}))
}
}
impl Storage for MemStorage {
fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<()> {
let data = self.0.data.lock().unwrap();
let offset = offset as usize;
let end = offset
.checked_add(buf.len())
.filter(|&end| end <= data.len())
.ok_or_else(|| Error::Io(std::io::Error::from(std::io::ErrorKind::UnexpectedEof)))?;
buf.copy_from_slice(&data[offset..end]);
Ok(())
}
fn write_at(&self, buf: &[u8], offset: u64) -> Result<()> {
let mut data = self.0.data.lock().unwrap();
let offset = offset as usize;
let end = offset
.checked_add(buf.len())
.filter(|&end| end <= data.len())
.ok_or_else(|| Error::Io(std::io::Error::from(std::io::ErrorKind::WriteZero)))?;
data[offset..end].copy_from_slice(buf);
Ok(())
}
fn size(&self) -> u64 {
self.0.data.lock().unwrap().len() as u64
}
fn close(self) -> Result<()> {
Ok(())
}
fn store_u32_at(&self, offset: u64, value: u32) -> Result<()> {
{
let mut data = self.0.data.lock().unwrap();
let offset = offset as usize;
let end = offset
.checked_add(4)
.filter(|&end| end <= data.len())
.ok_or_else(|| Error::Io(std::io::Error::from(std::io::ErrorKind::WriteZero)))?;
data[offset..end].copy_from_slice(&value.to_le_bytes());
}
self.0.changed.notify_all();
Ok(())
}
fn supports_wait(&self) -> bool {
true
}
fn wait_u32_at(&self, offset: u64, old: u32, timeout: Option<Duration>) {
let offset = offset as usize;
let Ok(data) = self.0.data.lock() else {
return;
};
let already_changed = match data.get(offset..offset + 4) {
Some(b) => u32::from_le_bytes(b.try_into().unwrap()) != old,
None => true,
};
if already_changed {
return;
}
match timeout {
None => drop(self.0.changed.wait(data)),
Some(d) => drop(self.0.changed.wait_timeout(data, d)),
}
}
}