use crate::error::CRDTResult;
use crate::memory::MemoryConfig;
use crate::traits::CRDT;
pub trait SafetyCRDT<C: MemoryConfig>: CRDT<C> {
type SafetyLevel: PartialOrd + Copy;
fn safety_level(&self) -> Self::SafetyLevel;
fn safety_merge(&mut self, other: &Self) -> CRDTResult<()>;
fn validate_safety(&self) -> CRDTResult<()>;
fn can_safely_merge(&self, other: &Self) -> bool;
fn min_safety_level(&self) -> Self::SafetyLevel;
fn set_safety_level(&mut self, level: Self::SafetyLevel) -> CRDTResult<()>;
fn safety_check(&self) -> CRDTResult<SafetyStatus>;
fn safety_metadata(&self) -> SafetyMetadata<Self::SafetyLevel>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SafetyStatus {
pub is_safe: bool,
pub compliance_level: u8,
pub violation_count: u32,
pub last_check_time: u32,
}
impl SafetyStatus {
pub const fn safe() -> Self {
Self {
is_safe: true,
compliance_level: 100,
violation_count: 0,
last_check_time: 0,
}
}
pub const fn unsafe_with_violations(violations: u32) -> Self {
Self {
is_safe: false,
compliance_level: 0,
violation_count: violations,
last_check_time: 0,
}
}
pub const fn is_critical(&self) -> bool {
!self.is_safe && self.violation_count > 0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SafetyMetadata<S> {
pub safety_level: S,
pub min_safety_level: S,
pub certification_level: CertificationLevel,
pub last_validation: u32,
pub check_interval: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum CertificationLevel {
None = 0,
Basic = 1,
Standard = 2,
High = 3,
Critical = 4,
}
pub trait FailSafeCRDT<C: MemoryConfig>: SafetyCRDT<C> {
fn enter_fail_safe_mode(&mut self) -> CRDTResult<()>;
fn exit_fail_safe_mode(&mut self) -> CRDTResult<()>;
fn is_in_fail_safe_mode(&self) -> bool;
fn safe_shutdown(&mut self) -> CRDTResult<()>;
fn recover_from_failure(&mut self) -> CRDTResult<()>;
fn failure_state(&self) -> FailureState;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FailureState {
Normal,
Degraded,
FailSafe,
Critical,
Shutdown,
}
pub trait SafetyMonitor<C: MemoryConfig>: SafetyCRDT<C> {
fn start_monitoring(&mut self) -> CRDTResult<()>;
fn stop_monitoring(&mut self) -> CRDTResult<()>;
fn is_monitoring_active(&self) -> bool;
fn periodic_safety_check(&mut self) -> CRDTResult<SafetyStatus>;
fn set_check_interval(&mut self, interval_cycles: u32);
fn check_interval(&self) -> u32;
fn register_violation(&mut self, violation: SafetyViolation);
fn violation_history(&self) -> &[SafetyViolation];
fn clear_violations(&mut self);
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SafetyViolation {
pub violation_type: ViolationType,
pub severity: u8,
pub timestamp: u32,
pub safety_level: u8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ViolationType {
SafetyLevelDowngrade,
IntegrityFailure,
TimeoutViolation,
ResourceViolation,
ProtocolViolation,
Custom(u8),
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::CRDTError;
use crate::memory::DefaultConfig;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
enum TestSafetyLevel {
Low = 1,
Medium = 2,
High = 3,
}
struct MockSafetyCRDT {
value: u32,
safety_level: TestSafetyLevel,
fail_safe_mode: bool,
}
impl MockSafetyCRDT {
fn new(safety_level: TestSafetyLevel) -> Self {
Self {
value: 0,
safety_level,
fail_safe_mode: false,
}
}
}
impl CRDT<DefaultConfig> for MockSafetyCRDT {
type Error = CRDTError;
fn merge(&mut self, other: &Self) -> CRDTResult<()> {
self.value = self.value.max(other.value);
Ok(())
}
fn eq(&self, other: &Self) -> bool {
self.value == other.value && self.safety_level == other.safety_level
}
fn size_bytes(&self) -> usize {
core::mem::size_of::<Self>()
}
fn validate(&self) -> CRDTResult<()> {
Ok(())
}
fn state_hash(&self) -> u32 {
self.value
}
fn can_merge(&self, _other: &Self) -> bool {
true
}
}
impl SafetyCRDT<DefaultConfig> for MockSafetyCRDT {
type SafetyLevel = TestSafetyLevel;
fn safety_level(&self) -> Self::SafetyLevel {
self.safety_level
}
fn safety_merge(&mut self, other: &Self) -> CRDTResult<()> {
if other.safety_level > self.safety_level {
self.value = other.value;
self.safety_level = other.safety_level;
} else if other.safety_level == self.safety_level {
self.value = self.value.max(other.value);
}
Ok(())
}
fn validate_safety(&self) -> CRDTResult<()> {
if self.fail_safe_mode && self.safety_level < TestSafetyLevel::Medium {
return Err(CRDTError::InvalidSafetyLevel);
}
Ok(())
}
fn can_safely_merge(&self, other: &Self) -> bool {
!self.fail_safe_mode || other.safety_level >= TestSafetyLevel::Medium
}
fn min_safety_level(&self) -> Self::SafetyLevel {
TestSafetyLevel::Low
}
fn set_safety_level(&mut self, level: Self::SafetyLevel) -> CRDTResult<()> {
if level < self.min_safety_level() {
return Err(CRDTError::InvalidSafetyLevel);
}
self.safety_level = level;
Ok(())
}
fn safety_check(&self) -> CRDTResult<SafetyStatus> {
if self.validate_safety().is_ok() {
Ok(SafetyStatus::safe())
} else {
Ok(SafetyStatus::unsafe_with_violations(1))
}
}
fn safety_metadata(&self) -> SafetyMetadata<Self::SafetyLevel> {
SafetyMetadata {
safety_level: self.safety_level,
min_safety_level: self.min_safety_level(),
certification_level: CertificationLevel::Standard,
last_validation: 0,
check_interval: 1000,
}
}
}
impl FailSafeCRDT<DefaultConfig> for MockSafetyCRDT {
fn enter_fail_safe_mode(&mut self) -> CRDTResult<()> {
self.fail_safe_mode = true;
Ok(())
}
fn exit_fail_safe_mode(&mut self) -> CRDTResult<()> {
self.fail_safe_mode = false;
Ok(())
}
fn is_in_fail_safe_mode(&self) -> bool {
self.fail_safe_mode
}
fn safe_shutdown(&mut self) -> CRDTResult<()> {
self.fail_safe_mode = true;
Ok(())
}
fn recover_from_failure(&mut self) -> CRDTResult<()> {
if self.safety_check()?.is_safe {
self.fail_safe_mode = false;
}
Ok(())
}
fn failure_state(&self) -> FailureState {
if self.fail_safe_mode {
FailureState::FailSafe
} else {
FailureState::Normal
}
}
}
#[test]
fn test_safety_crdt() {
let mut crdt1 = MockSafetyCRDT::new(TestSafetyLevel::Medium);
let crdt2 = MockSafetyCRDT::new(TestSafetyLevel::High);
assert_eq!(crdt1.safety_level(), TestSafetyLevel::Medium);
assert!(crdt1.can_safely_merge(&crdt2));
assert!(crdt1.safety_merge(&crdt2).is_ok());
assert_eq!(crdt1.safety_level(), TestSafetyLevel::High);
let status = crdt1.safety_check().unwrap();
assert!(status.is_safe);
}
#[test]
fn test_fail_safe_crdt() {
let mut crdt = MockSafetyCRDT::new(TestSafetyLevel::Low);
assert!(!crdt.is_in_fail_safe_mode());
assert_eq!(crdt.failure_state(), FailureState::Normal);
assert!(crdt.enter_fail_safe_mode().is_ok());
assert!(crdt.is_in_fail_safe_mode());
assert_eq!(crdt.failure_state(), FailureState::FailSafe);
assert!(crdt.exit_fail_safe_mode().is_ok());
assert!(!crdt.is_in_fail_safe_mode());
}
#[test]
fn test_safety_status() {
let safe_status = SafetyStatus::safe();
assert!(safe_status.is_safe);
assert!(!safe_status.is_critical());
let unsafe_status = SafetyStatus::unsafe_with_violations(3);
assert!(!unsafe_status.is_safe);
assert!(unsafe_status.is_critical());
assert_eq!(unsafe_status.violation_count, 3);
}
}