pub mod checksum;
pub mod corruption;
pub mod types;
pub mod version;
pub use checksum::{ChecksumAlgorithm, ChecksumConfig, ChecksumVerifier};
pub use corruption::{CorruptionConfig, CorruptionDetector, CorruptionResult};
pub use types::{DataFormat, DataMetadata, IntegrityResult, IntegrityStats};
pub use version::{VersionConfig, VersionVerifier};
use std::sync::Arc;
use tokio::sync::RwLock;
#[derive(Debug, Clone, PartialEq)]
pub struct IntegrityConfig {
pub checksum_config: ChecksumConfig,
pub version_config: VersionConfig,
pub corruption_config: CorruptionConfig,
}
impl Default for IntegrityConfig {
fn default() -> Self {
Self {
checksum_config: ChecksumConfig::default(),
version_config: VersionConfig::default(),
corruption_config: CorruptionConfig::default(),
}
}
}
#[derive(Debug, Clone)]
pub struct DataIntegrity {
checksum_verifier: ChecksumVerifier,
version_verifier: VersionVerifier,
corruption_detector: CorruptionDetector,
stats: Arc<RwLock<IntegrityStats>>,
initialized: bool,
}
impl DataIntegrity {
pub fn new() -> Self {
Self {
checksum_verifier: ChecksumVerifier::new(),
version_verifier: VersionVerifier::new(),
corruption_detector: CorruptionDetector::new(),
stats: Arc::new(RwLock::new(IntegrityStats::new())),
initialized: false,
}
}
pub fn with_config(config: IntegrityConfig) -> Self {
Self {
checksum_verifier: ChecksumVerifier::with_config(config.checksum_config),
version_verifier: VersionVerifier::with_config(config.version_config),
corruption_detector: CorruptionDetector::with_config(config.corruption_config),
stats: Arc::new(RwLock::new(IntegrityStats::new())),
initialized: false,
}
}
pub async fn initialize(&mut self) -> Result<(), IntegrityError> {
if self.initialized {
return Err(IntegrityError::AlreadyInitialized);
}
self.checksum_verifier = ChecksumVerifier::new();
self.version_verifier = VersionVerifier::new();
self.corruption_detector = CorruptionDetector::new();
self.initialized = true;
Ok(())
}
pub async fn shutdown(&mut self) -> Result<(), IntegrityError> {
if !self.initialized {
return Err(IntegrityError::NotInitialized);
}
self.checksum_verifier.clear_cache();
self.version_verifier.clear_versions();
self.corruption_detector.clear_stats();
self.initialized = false;
Ok(())
}
pub async fn verify_integrity(
&mut self,
data: &[u8],
key: &str,
) -> Result<IntegrityResult, IntegrityError> {
if !self.initialized {
return Err(IntegrityError::NotInitialized);
}
let metadata = DataMetadata::new(DataFormat::Binary, data.len());
let checksum_valid = if self.checksum_verifier.config().verify_on_read {
if let Some(expected_checksum) = self.checksum_verifier.get_cached_checksum(key) {
self.checksum_verifier
.verify_checksum(data, expected_checksum)?
} else {
true }
} else {
true
};
let version_valid = if self.version_verifier.config().verify_on_read {
let current_version = self.version_verifier.get_version(key);
self.version_verifier.verify_version(key, current_version)?
} else {
true
};
let corruption_result = self.corruption_detector.detect_corruption(data, key);
let corruption_detected = corruption_result.is_corrupted;
let is_valid = checksum_valid && version_valid && !corruption_detected;
{
let mut stats = self.stats.write().await;
stats.record_verification(is_valid);
if corruption_detected {
stats.record_corruption_detection();
}
if corruption_result.recovery_attempted {
stats.record_recovery_attempt(corruption_result.recovery_successful);
}
}
let result = if is_valid {
IntegrityResult::valid(metadata)
} else {
let error_msg = format!(
"Integrity check failed: checksum={}, version={}, corruption={}",
checksum_valid, version_valid, corruption_detected
);
IntegrityResult::invalid(error_msg, metadata)
};
Ok(result)
}
pub async fn compute_checksum(
&mut self,
data: &[u8],
key: &str,
) -> Result<String, IntegrityError> {
if !self.initialized {
return Err(IntegrityError::NotInitialized);
}
if !self.checksum_verifier.config().compute_on_write {
return Err(IntegrityError::ChecksumComputationDisabled);
}
self.checksum_verifier.compute_checksum(data, key)
}
pub async fn increment_version(&mut self, key: &str) -> Result<u64, IntegrityError> {
if !self.initialized {
return Err(IntegrityError::NotInitialized);
}
if !self.version_verifier.config().increment_on_write {
return Err(IntegrityError::VersionIncrementDisabled);
}
Ok(self.version_verifier.increment_version(key))
}
pub async fn get_stats(&self) -> IntegrityStats {
self.stats.read().await.clone()
}
pub fn is_initialized(&self) -> bool {
self.initialized
}
pub fn checksum_verifier(&self) -> &ChecksumVerifier {
&self.checksum_verifier
}
pub fn version_verifier(&self) -> &VersionVerifier {
&self.version_verifier
}
pub fn corruption_detector(&self) -> &CorruptionDetector {
&self.corruption_detector
}
}
impl Default for DataIntegrity {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IntegrityError {
NotInitialized,
AlreadyInitialized,
ChecksumMismatch,
VersionMismatch {
key: String,
expected: u64,
actual: u64,
},
CorruptionDetected,
ChecksumComputationDisabled,
VersionIncrementDisabled,
InvalidDataFormat,
OperationFailed(String),
}
impl std::fmt::Display for IntegrityError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IntegrityError::NotInitialized => write!(f, "Data integrity system not initialized"),
IntegrityError::AlreadyInitialized => {
write!(f, "Data integrity system already initialized")
}
IntegrityError::ChecksumMismatch => write!(f, "Checksum mismatch detected"),
IntegrityError::VersionMismatch {
key,
expected,
actual,
} => {
write!(
f,
"Version mismatch for key '{}': expected {}, got {}",
key, expected, actual
)
}
IntegrityError::CorruptionDetected => write!(f, "Data corruption detected"),
IntegrityError::ChecksumComputationDisabled => {
write!(f, "Checksum computation is disabled")
}
IntegrityError::VersionIncrementDisabled => write!(f, "Version increment is disabled"),
IntegrityError::InvalidDataFormat => write!(f, "Invalid data format"),
IntegrityError::OperationFailed(msg) => write!(f, "Operation failed: {}", msg),
}
}
}
impl std::error::Error for IntegrityError {}
#[cfg(test)]
mod integration_tests {
use super::*;
#[tokio::test]
async fn test_data_integrity_creation() {
let mut integrity = DataIntegrity::new();
assert!(!integrity.is_initialized());
integrity.initialize().await.unwrap();
assert!(integrity.is_initialized());
}
#[tokio::test]
async fn test_data_integrity_with_config() {
let config = IntegrityConfig::default();
let mut integrity = DataIntegrity::with_config(config);
integrity.initialize().await.unwrap();
assert!(integrity.is_initialized());
}
#[tokio::test]
async fn test_data_integrity_initialization() {
let mut integrity = DataIntegrity::new();
let result = integrity.initialize().await;
assert!(result.is_ok());
assert!(integrity.is_initialized());
let result = integrity.initialize().await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_data_integrity_shutdown() {
let mut integrity = DataIntegrity::new();
integrity.initialize().await.unwrap();
assert!(integrity.is_initialized());
let result = integrity.shutdown().await;
assert!(result.is_ok());
assert!(!integrity.is_initialized());
}
#[tokio::test]
async fn test_verify_integrity() {
let mut integrity = DataIntegrity::new();
integrity.initialize().await.unwrap();
let data = b"test data";
let key = "test_key";
let result = integrity.verify_integrity(data, key).await.unwrap();
assert!(result.is_valid);
assert!(result.checksum_valid);
assert!(result.version_valid);
assert!(!result.corruption_detected);
}
#[tokio::test]
async fn test_compute_checksum() {
let mut integrity = DataIntegrity::new();
integrity.initialize().await.unwrap();
let data = b"test data";
let key = "test_key";
let checksum = integrity.compute_checksum(data, key).await.unwrap();
assert!(!checksum.is_empty());
}
#[tokio::test]
async fn test_increment_version() {
let mut integrity = DataIntegrity::new();
integrity.initialize().await.unwrap();
let key = "test_key";
let version1 = integrity.increment_version(key).await.unwrap();
let version2 = integrity.increment_version(key).await.unwrap();
assert_eq!(version1, 1);
assert_eq!(version2, 2);
}
#[tokio::test]
async fn test_get_stats() {
let mut integrity = DataIntegrity::new();
integrity.initialize().await.unwrap();
let data = b"test data";
let key = "test_key";
integrity.verify_integrity(data, key).await.unwrap();
integrity.compute_checksum(data, key).await.unwrap();
integrity.increment_version(key).await.unwrap();
let stats = integrity.get_stats().await;
assert!(stats.total_verifications > 0);
assert!(stats.successful_verifications > 0);
}
#[tokio::test]
async fn test_operations_before_initialization() {
let mut integrity = DataIntegrity::new();
let data = b"test data";
let key = "test_key";
assert!(integrity.verify_integrity(data, key).await.is_err());
assert!(integrity.compute_checksum(data, key).await.is_err());
assert!(integrity.increment_version(key).await.is_err());
}
}