use std::path::PathBuf;
use std::sync::atomic::{AtomicU8, Ordering};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub struct Seq(u8);
impl Seq {
#[must_use]
pub const fn new() -> Self {
Self(0)
}
#[must_use]
pub const fn get(self) -> u8 {
self.0
}
pub fn next_value(&mut self) -> u8 {
let current = self.0;
self.0 = self.0.wrapping_add(1);
current
}
pub fn reset(&mut self) {
self.0 = 0;
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub struct BdSeq(u8);
impl BdSeq {
#[must_use]
pub const fn new(start: u8) -> Self {
Self(start)
}
#[must_use]
pub const fn get(self) -> u8 {
self.0
}
pub fn advance(&mut self) {
self.0 = self.0.wrapping_add(1);
}
}
pub trait BdSeqStore {
fn load_next_death(&self) -> std::io::Result<u8>;
fn store_next_death(&self, value: u8) -> std::io::Result<()>;
}
impl<B: BdSeqStore + ?Sized> BdSeqStore for &B {
fn load_next_death(&self) -> std::io::Result<u8> {
(**self).load_next_death()
}
fn store_next_death(&self, value: u8) -> std::io::Result<()> {
(**self).store_next_death(value)
}
}
#[derive(Debug, Default)]
pub struct InMemoryBdSeqStore {
value: AtomicU8,
}
impl InMemoryBdSeqStore {
#[must_use]
pub fn new(start: u8) -> Self {
Self {
value: AtomicU8::new(start),
}
}
}
impl BdSeqStore for InMemoryBdSeqStore {
fn load_next_death(&self) -> std::io::Result<u8> {
Ok(self.value.load(Ordering::SeqCst))
}
fn store_next_death(&self, value: u8) -> std::io::Result<()> {
self.value.store(value, Ordering::SeqCst);
Ok(())
}
}
#[derive(Clone, Debug)]
pub struct FileBdSeqStore {
path: PathBuf,
}
impl FileBdSeqStore {
#[must_use]
pub fn new(path: impl Into<PathBuf>) -> Self {
Self { path: path.into() }
}
}
impl BdSeqStore for FileBdSeqStore {
fn load_next_death(&self) -> std::io::Result<u8> {
match std::fs::read_to_string(&self.path) {
Ok(s) => s.trim().parse::<u8>().map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!("corrupt bdSeq file {:?}: {e}", self.path),
)
}),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(0),
Err(e) => Err(e),
}
}
fn store_next_death(&self, value: u8) -> std::io::Result<()> {
let file_name = self
.path
.file_name()
.map(|n| n.to_string_lossy().into_owned())
.unwrap_or_else(|| "bdseq".to_owned());
let tmp = self
.path
.with_file_name(format!("{file_name}.tmp.{}", std::process::id()));
std::fs::write(&tmp, value.to_string())?;
std::fs::rename(&tmp, &self.path)
}
}