use std::{fmt, sync::Arc};
pub(crate) const MAX_SLICES_PER_FILE: usize = 32_768;
pub(crate) const MAX_TOTAL_INPUT_SLICES: usize = 32_768;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FileId(pub(crate) [u8; 16]);
impl FileId {
pub fn from_bytes(bytes: [u8; 16]) -> Self {
Self(bytes)
}
pub fn as_bytes(&self) -> &[u8; 16] {
&self.0
}
}
impl fmt::Debug for FileId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FileId(")?;
for b in &self.0 {
write!(f, "{b:02x}")?;
}
write!(f, ")")
}
}
impl fmt::Display for FileId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for b in &self.0 {
write!(f, "{b:02x}")?;
}
Ok(())
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct RecoverySetId(pub(crate) [u8; 16]);
impl RecoverySetId {
pub fn from_bytes(bytes: [u8; 16]) -> Self {
Self(bytes)
}
pub fn as_bytes(&self) -> &[u8; 16] {
&self.0
}
}
impl fmt::Debug for RecoverySetId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "RecoverySetId(")?;
for b in &self.0 {
write!(f, "{b:02x}")?;
}
write!(f, ")")
}
}
impl fmt::Display for RecoverySetId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for b in &self.0 {
write!(f, "{b:02x}")?;
}
Ok(())
}
}
pub type SliceIndex = u32;
pub type RecoveryExponent = u32;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SliceChecksum {
pub crc32: u32,
pub md5: [u8; 16],
}
#[derive(Clone)]
pub struct CancellationToken(std::sync::Arc<std::sync::atomic::AtomicBool>);
impl CancellationToken {
pub fn new() -> Self {
Self(std::sync::Arc::new(std::sync::atomic::AtomicBool::new(
false,
)))
}
pub fn cancel(&self) {
self.0.store(true, std::sync::atomic::Ordering::Relaxed);
}
pub fn is_cancelled(&self) -> bool {
self.0.load(std::sync::atomic::Ordering::Relaxed)
}
}
impl Default for CancellationToken {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct ProgressUpdate {
pub stage: ProgressStage,
pub current: u32,
pub total: u32,
pub bytes_processed: u64,
pub total_bytes: Option<u64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProgressStage {
Verifying,
ReadingRecovery,
Repairing,
WritingRepaired,
}
pub type ProgressCallback = Arc<dyn Fn(ProgressUpdate) + Send + Sync>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn file_id_display() {
let id = FileId([
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54,
0x32, 0x10,
]);
assert_eq!(format!("{id}"), "0123456789abcdeffedcba9876543210");
}
#[test]
fn file_id_debug() {
let id = FileId([0; 16]);
let dbg = format!("{id:?}");
assert!(dbg.starts_with("FileId("));
assert!(dbg.ends_with(')'));
}
#[test]
fn recovery_set_id_roundtrip() {
let bytes = [1u8; 16];
let id = RecoverySetId::from_bytes(bytes);
assert_eq!(*id.as_bytes(), bytes);
}
#[test]
fn file_id_equality() {
let a = FileId([0xAA; 16]);
let b = FileId([0xAA; 16]);
let c = FileId([0xBB; 16]);
assert_eq!(a, b);
assert_ne!(a, c);
}
}