use alloc::string::String;
use alloc::vec::Vec;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum WTemporalOp {
Create = 0,
Write = 1,
Delete = 2,
SetAttr = 3,
Rename = 4,
Link = 5,
Truncate = 6,
Snapshot = 7,
Clone = 8,
DatasetCreate = 9,
DatasetDestroy = 10,
PoolImport = 11,
PoolExport = 12,
ScrubStart = 13,
ScrubComplete = 14,
Repair = 15,
}
impl WTemporalOp {
pub const fn name(&self) -> &'static str {
match self {
WTemporalOp::Create => "create",
WTemporalOp::Write => "write",
WTemporalOp::Delete => "delete",
WTemporalOp::SetAttr => "setattr",
WTemporalOp::Rename => "rename",
WTemporalOp::Link => "link",
WTemporalOp::Truncate => "truncate",
WTemporalOp::Snapshot => "snapshot",
WTemporalOp::Clone => "clone",
WTemporalOp::DatasetCreate => "dataset_create",
WTemporalOp::DatasetDestroy => "dataset_destroy",
WTemporalOp::PoolImport => "pool_import",
WTemporalOp::PoolExport => "pool_export",
WTemporalOp::ScrubStart => "scrub_start",
WTemporalOp::ScrubComplete => "scrub_complete",
WTemporalOp::Repair => "repair",
}
}
pub const fn modifies_data(&self) -> bool {
matches!(
self,
WTemporalOp::Write | WTemporalOp::Truncate | WTemporalOp::Repair
)
}
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(WTemporalOp::Create),
1 => Some(WTemporalOp::Write),
2 => Some(WTemporalOp::Delete),
3 => Some(WTemporalOp::SetAttr),
4 => Some(WTemporalOp::Rename),
5 => Some(WTemporalOp::Link),
6 => Some(WTemporalOp::Truncate),
7 => Some(WTemporalOp::Snapshot),
8 => Some(WTemporalOp::Clone),
9 => Some(WTemporalOp::DatasetCreate),
10 => Some(WTemporalOp::DatasetDestroy),
11 => Some(WTemporalOp::PoolImport),
12 => Some(WTemporalOp::PoolExport),
13 => Some(WTemporalOp::ScrubStart),
14 => Some(WTemporalOp::ScrubComplete),
15 => Some(WTemporalOp::Repair),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct WTemporalHash {
pub bytes: [u8; 32],
}
impl WTemporalHash {
pub const fn new(bytes: [u8; 32]) -> Self {
Self { bytes }
}
pub const fn genesis() -> Self {
Self { bytes: [0u8; 32] }
}
pub fn is_genesis(&self) -> bool {
self.bytes == [0u8; 32]
}
pub fn to_hex(&self) -> String {
let mut result = String::with_capacity(64);
for byte in &self.bytes {
use core::fmt::Write;
let _ = write!(result, "{:02x}", byte);
}
result
}
}
#[derive(Debug, Clone)]
pub struct WTemporalEntry {
pub timestamp_ns: u64,
pub operation: WTemporalOp,
pub dataset_id: u64,
pub object_id: u64,
pub user_id: u64,
pub process_id: u32,
pub prev_hash: WTemporalHash,
pub context: Option<String>,
pub data_size: u64,
pub data_offset: u64,
pub hash: WTemporalHash,
}
impl WTemporalEntry {
pub fn new(
operation: WTemporalOp,
dataset_id: u64,
object_id: u64,
user_id: u64,
prev_hash: WTemporalHash,
) -> Self {
Self {
timestamp_ns: 0, operation,
dataset_id,
object_id,
user_id,
process_id: 0,
prev_hash,
context: None,
data_size: 0,
data_offset: 0,
hash: WTemporalHash::genesis(),
}
}
pub fn with_context(mut self, context: String) -> Self {
self.context = Some(context);
self
}
pub fn with_data_info(mut self, offset: u64, size: u64) -> Self {
self.data_offset = offset;
self.data_size = size;
self
}
}
impl Default for WTemporalEntry {
fn default() -> Self {
Self::new(WTemporalOp::Create, 0, 0, 0, WTemporalHash::genesis())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WTemporalError {
LedgerFull,
ChainBroken,
EntryNotFound,
InvalidEntry,
ConcurrentModification,
StorageError,
NotAvailable,
}
impl WTemporalError {
pub const fn description(&self) -> &'static str {
match self {
WTemporalError::LedgerFull => "Ledger storage exhausted",
WTemporalError::ChainBroken => "Chain integrity violation",
WTemporalError::EntryNotFound => "Entry not found",
WTemporalError::InvalidEntry => "Invalid entry data",
WTemporalError::ConcurrentModification => "Concurrent modification",
WTemporalError::StorageError => "Storage I/O error",
WTemporalError::NotAvailable => "W_temporal not available",
}
}
}
#[derive(Debug, Clone, Default)]
pub struct WTemporalStats {
pub total_entries: u64,
pub session_entries: u64,
pub verifications: u64,
pub verification_failures: u64,
pub storage_used: u64,
pub tip_hash: WTemporalHash,
}
pub trait WTemporalProvider: Send + Sync {
fn record(&self, entry: WTemporalEntry) -> Result<WTemporalHash, WTemporalError>;
fn verify_chain(&self, tip_hash: &WTemporalHash) -> Result<bool, WTemporalError>;
fn get_entry(&self, hash: &WTemporalHash) -> Option<WTemporalEntry>;
fn tip_hash(&self) -> WTemporalHash;
fn statistics(&self) -> WTemporalStats {
WTemporalStats::default()
}
fn query_object(
&self,
_dataset_id: u64,
_object_id: u64,
_limit: usize,
) -> Vec<WTemporalEntry> {
Vec::new()
}
fn query_time_range(&self, _start_ns: u64, _end_ns: u64, _limit: usize) -> Vec<WTemporalEntry> {
Vec::new()
}
}
#[derive(Debug, Clone)]
pub struct AccessEvent {
pub block_id: u64,
pub timestamp_ns: u64,
pub access_type: AccessType,
pub size: u32,
pub latency_ns: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum AccessType {
SequentialRead = 0,
RandomRead = 1,
SequentialWrite = 2,
RandomWrite = 3,
Metadata = 4,
Prefetch = 5,
}
impl AccessType {
pub const fn is_read(&self) -> bool {
matches!(
self,
AccessType::SequentialRead | AccessType::RandomRead | AccessType::Prefetch
)
}
pub const fn is_write(&self) -> bool {
matches!(self, AccessType::SequentialWrite | AccessType::RandomWrite)
}
pub const fn is_sequential(&self) -> bool {
matches!(
self,
AccessType::SequentialRead | AccessType::SequentialWrite
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
pub enum StorageTier {
LocalDram = 0,
CxlNear = 1,
CxlFar = 2,
Nvme = 3,
Hdd = 4,
Cloud = 5,
}
impl StorageTier {
pub const fn name(&self) -> &'static str {
match self {
StorageTier::LocalDram => "local_dram",
StorageTier::CxlNear => "cxl_near",
StorageTier::CxlFar => "cxl_far",
StorageTier::Nvme => "nvme",
StorageTier::Hdd => "hdd",
StorageTier::Cloud => "cloud",
}
}
pub const fn typical_latency_ns(&self) -> u64 {
match self {
StorageTier::LocalDram => 100,
StorageTier::CxlNear => 300,
StorageTier::CxlFar => 1000,
StorageTier::Nvme => 10_000,
StorageTier::Hdd => 5_000_000,
StorageTier::Cloud => 50_000_000,
}
}
}
#[derive(Debug, Clone)]
pub struct PlacementSuggestion {
pub tier: StorageTier,
pub priority: f64,
pub confidence: f64,
pub estimated_benefit_ns: u64,
pub migration_cost_bytes: u64,
}
impl PlacementSuggestion {
pub fn stay_put() -> Self {
Self {
tier: StorageTier::Nvme,
priority: 0.0,
confidence: 1.0,
estimated_benefit_ns: 0,
migration_cost_bytes: 0,
}
}
pub fn should_migrate(&self) -> bool {
self.priority > 0.5 && self.confidence > 0.7
}
}
impl Default for PlacementSuggestion {
fn default() -> Self {
Self::stay_put()
}
}
#[derive(Debug, Clone, Default)]
pub struct GravityStats {
pub blocks_tracked: u64,
pub events_processed: u64,
pub training_iterations: u64,
pub predictions_correct: u64,
pub predictions_total: u64,
pub migrations_triggered: u64,
pub bytes_migrated: u64,
}
impl GravityStats {
pub fn accuracy(&self) -> f64 {
if self.predictions_total == 0 {
return 0.0;
}
self.predictions_correct as f64 / self.predictions_total as f64
}
}
pub trait GravityProvider: Send + Sync {
fn calculate_mass(&self, block_id: u64, access_history: &[AccessEvent]) -> f64;
fn suggest_placement(&self, block_id: u64, mass: f64) -> PlacementSuggestion;
fn train(&self, events: &[AccessEvent]);
fn get_mass(&self, _block_id: u64) -> Option<f64> {
None
}
fn get_hot_blocks(&self, _min_mass: f64, _limit: usize) -> Vec<(u64, f64)> {
Vec::new()
}
fn get_cold_blocks(&self, _max_mass: f64, _limit: usize) -> Vec<(u64, f64)> {
Vec::new()
}
fn statistics(&self) -> GravityStats {
GravityStats::default()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum PiOperation {
Checksum = 0,
CompressLz4 = 1,
DecompressLz4 = 2,
CompressZstd = 3,
DecompressZstd = 4,
PatternSearch = 5,
MemCopy = 6,
MemCompare = 7,
AggregateSum = 8,
AggregateCount = 9,
XorParity = 10,
Encrypt = 11,
Decrypt = 12,
}
impl PiOperation {
pub const fn name(&self) -> &'static str {
match self {
PiOperation::Checksum => "checksum",
PiOperation::CompressLz4 => "compress_lz4",
PiOperation::DecompressLz4 => "decompress_lz4",
PiOperation::CompressZstd => "compress_zstd",
PiOperation::DecompressZstd => "decompress_zstd",
PiOperation::PatternSearch => "pattern_search",
PiOperation::MemCopy => "memcpy",
PiOperation::MemCompare => "memcmp",
PiOperation::AggregateSum => "aggregate_sum",
PiOperation::AggregateCount => "aggregate_count",
PiOperation::XorParity => "xor_parity",
PiOperation::Encrypt => "encrypt",
PiOperation::Decrypt => "decrypt",
}
}
pub const fn reads_data(&self) -> bool {
true }
pub const fn writes_data(&self) -> bool {
matches!(
self,
PiOperation::CompressLz4
| PiOperation::DecompressLz4
| PiOperation::CompressZstd
| PiOperation::DecompressZstd
| PiOperation::MemCopy
| PiOperation::XorParity
| PiOperation::Encrypt
| PiOperation::Decrypt
)
}
}
#[derive(Debug, Clone)]
pub struct PiResult {
pub operation: PiOperation,
pub success: bool,
pub result_value: i64,
pub execution_time_ns: u64,
pub bytes_processed: u64,
}
impl PiResult {
pub fn success(operation: PiOperation, result_value: i64) -> Self {
Self {
operation,
success: true,
result_value,
execution_time_ns: 0,
bytes_processed: 0,
}
}
pub fn failure(operation: PiOperation) -> Self {
Self {
operation,
success: false,
result_value: 0,
execution_time_ns: 0,
bytes_processed: 0,
}
}
}
impl Default for PiResult {
fn default() -> Self {
Self::failure(PiOperation::Checksum)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PiError {
NotSupported,
InvalidAddress,
MemoryNotAccessible,
Timeout,
HardwareError,
Busy,
NotAvailable,
}
impl PiError {
pub const fn description(&self) -> &'static str {
match self {
PiError::NotSupported => "Operation not supported",
PiError::InvalidAddress => "Invalid memory address",
PiError::MemoryNotAccessible => "Memory not accessible to PI unit",
PiError::Timeout => "Operation timed out",
PiError::HardwareError => "PI hardware error",
PiError::Busy => "PI unit busy",
PiError::NotAvailable => "PI not available",
}
}
}
#[derive(Debug, Clone, Default)]
pub struct PiCapabilities {
pub checksum: bool,
pub compress_lz4: bool,
pub compress_zstd: bool,
pub pattern_search: bool,
pub memory_ops: bool,
pub aggregation: bool,
pub xor_parity: bool,
pub encryption: bool,
pub max_data_size: usize,
pub unit_count: u32,
pub bandwidth_mbps: u32,
}
impl PiCapabilities {
pub fn supports(&self, op: PiOperation) -> bool {
match op {
PiOperation::Checksum => self.checksum,
PiOperation::CompressLz4 | PiOperation::DecompressLz4 => self.compress_lz4,
PiOperation::CompressZstd | PiOperation::DecompressZstd => self.compress_zstd,
PiOperation::PatternSearch => self.pattern_search,
PiOperation::MemCopy | PiOperation::MemCompare => self.memory_ops,
PiOperation::AggregateSum | PiOperation::AggregateCount => self.aggregation,
PiOperation::XorParity => self.xor_parity,
PiOperation::Encrypt | PiOperation::Decrypt => self.encryption,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct PiStats {
pub ops_executed: u64,
pub ops_fallback: u64,
pub bytes_processed: u64,
pub execution_time_ns: u64,
pub cycles_saved: u64,
pub energy_saved_uj: u64,
}
impl PiStats {
pub fn offload_ratio(&self) -> f64 {
let total = self.ops_executed + self.ops_fallback;
if total == 0 {
return 0.0;
}
self.ops_executed as f64 / total as f64
}
pub fn throughput_mbps(&self) -> f64 {
if self.execution_time_ns == 0 {
return 0.0;
}
(self.bytes_processed as f64 / 1_000_000.0)
/ (self.execution_time_ns as f64 / 1_000_000_000.0)
}
}
pub trait PiProvider: Send + Sync {
fn can_offload(&self, op: PiOperation) -> bool;
fn execute(&self, op: PiOperation, data_addr: u64, size: usize) -> Result<PiResult, PiError>;
fn execute_with_output(
&self,
op: PiOperation,
src_addr: u64,
src_size: usize,
_dst_addr: u64,
_dst_size: usize,
) -> Result<PiResult, PiError> {
self.execute(op, src_addr, src_size)
}
fn capabilities(&self) -> PiCapabilities;
fn statistics(&self) -> PiStats {
PiStats::default()
}
fn is_available(&self) -> bool {
false
}
}
pub struct NoOpWTemporalProvider;
impl NoOpWTemporalProvider {
pub const fn new() -> Self {
Self
}
}
impl Default for NoOpWTemporalProvider {
fn default() -> Self {
Self::new()
}
}
impl WTemporalProvider for NoOpWTemporalProvider {
fn record(&self, _entry: WTemporalEntry) -> Result<WTemporalHash, WTemporalError> {
Err(WTemporalError::NotAvailable)
}
fn verify_chain(&self, _tip_hash: &WTemporalHash) -> Result<bool, WTemporalError> {
Err(WTemporalError::NotAvailable)
}
fn get_entry(&self, _hash: &WTemporalHash) -> Option<WTemporalEntry> {
None
}
fn tip_hash(&self) -> WTemporalHash {
WTemporalHash::genesis()
}
}
static NOOP_WTEMPORAL: NoOpWTemporalProvider = NoOpWTemporalProvider::new();
pub struct NoOpGravityProvider;
impl NoOpGravityProvider {
pub const fn new() -> Self {
Self
}
}
impl Default for NoOpGravityProvider {
fn default() -> Self {
Self::new()
}
}
impl GravityProvider for NoOpGravityProvider {
fn calculate_mass(&self, _block_id: u64, _access_history: &[AccessEvent]) -> f64 {
1.0
}
fn suggest_placement(&self, _block_id: u64, _mass: f64) -> PlacementSuggestion {
PlacementSuggestion::stay_put()
}
fn train(&self, _events: &[AccessEvent]) {
}
}
static NOOP_GRAVITY: NoOpGravityProvider = NoOpGravityProvider::new();
pub struct NoOpPiProvider;
impl NoOpPiProvider {
pub const fn new() -> Self {
Self
}
}
impl Default for NoOpPiProvider {
fn default() -> Self {
Self::new()
}
}
impl PiProvider for NoOpPiProvider {
fn can_offload(&self, _op: PiOperation) -> bool {
false
}
fn execute(
&self,
_op: PiOperation,
_data_addr: u64,
_size: usize,
) -> Result<PiResult, PiError> {
Err(PiError::NotAvailable)
}
fn capabilities(&self) -> PiCapabilities {
PiCapabilities::default()
}
fn is_available(&self) -> bool {
false
}
}
static NOOP_PI: NoOpPiProvider = NoOpPiProvider::new();
static WTEMPORAL_PROVIDER: spin::Once<&'static dyn WTemporalProvider> = spin::Once::new();
static GRAVITY_PROVIDER: spin::Once<&'static dyn GravityProvider> = spin::Once::new();
static PI_PROVIDER: spin::Once<&'static dyn PiProvider> = spin::Once::new();
pub fn register_wtemporal_provider(provider: &'static dyn WTemporalProvider) {
WTEMPORAL_PROVIDER.call_once(|| provider);
}
pub fn get_wtemporal_provider() -> &'static dyn WTemporalProvider {
WTEMPORAL_PROVIDER.get().copied().unwrap_or(&NOOP_WTEMPORAL)
}
pub fn is_wtemporal_available() -> bool {
WTEMPORAL_PROVIDER.get().is_some()
}
pub fn register_gravity_provider(provider: &'static dyn GravityProvider) {
GRAVITY_PROVIDER.call_once(|| provider);
}
pub fn get_gravity_provider() -> &'static dyn GravityProvider {
GRAVITY_PROVIDER.get().copied().unwrap_or(&NOOP_GRAVITY)
}
pub fn is_gravity_available() -> bool {
GRAVITY_PROVIDER.get().is_some()
}
pub fn register_pi_provider(provider: &'static dyn PiProvider) {
PI_PROVIDER.call_once(|| provider);
}
pub fn get_pi_provider() -> &'static dyn PiProvider {
PI_PROVIDER.get().copied().unwrap_or(&NOOP_PI)
}
pub fn is_pi_available() -> bool {
PI_PROVIDER.get().is_some_and(|p| p.is_available())
}
pub fn record_operation(entry: WTemporalEntry) -> Option<WTemporalHash> {
if !is_wtemporal_available() {
return None;
}
get_wtemporal_provider().record(entry).ok()
}
pub fn calculate_block_mass(block_id: u64, access_history: &[AccessEvent]) -> f64 {
get_gravity_provider().calculate_mass(block_id, access_history)
}
pub fn suggest_block_placement(block_id: u64, mass: f64) -> PlacementSuggestion {
get_gravity_provider().suggest_placement(block_id, mass)
}
pub fn execute_pi_operation(
op: PiOperation,
data_addr: u64,
size: usize,
) -> Result<PiResult, PiError> {
let provider = get_pi_provider();
if !provider.can_offload(op) {
return Err(PiError::NotSupported);
}
provider.execute(op, data_addr, size)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_wtemporal_op_properties() {
assert!(WTemporalOp::Write.modifies_data());
assert!(!WTemporalOp::Create.modifies_data());
assert!(!WTemporalOp::Delete.modifies_data());
assert!(WTemporalOp::Truncate.modifies_data());
assert!(WTemporalOp::Repair.modifies_data());
}
#[test]
fn test_wtemporal_op_from_u8() {
assert_eq!(WTemporalOp::from_u8(0), Some(WTemporalOp::Create));
assert_eq!(WTemporalOp::from_u8(1), Some(WTemporalOp::Write));
assert_eq!(WTemporalOp::from_u8(255), None);
}
#[test]
fn test_wtemporal_hash() {
let genesis = WTemporalHash::genesis();
assert!(genesis.is_genesis());
let hash = WTemporalHash::new([1u8; 32]);
assert!(!hash.is_genesis());
assert_eq!(hash.to_hex().len(), 64);
}
#[test]
fn test_wtemporal_entry_builder() {
let entry = WTemporalEntry::new(WTemporalOp::Write, 1, 2, 1000, WTemporalHash::genesis())
.with_context("test.txt".into())
.with_data_info(0, 1024);
assert_eq!(entry.operation, WTemporalOp::Write);
assert_eq!(entry.dataset_id, 1);
assert_eq!(entry.object_id, 2);
assert_eq!(entry.user_id, 1000);
assert_eq!(entry.context, Some("test.txt".into()));
assert_eq!(entry.data_size, 1024);
}
#[test]
fn test_access_type_properties() {
assert!(AccessType::SequentialRead.is_read());
assert!(AccessType::RandomRead.is_read());
assert!(!AccessType::SequentialWrite.is_read());
assert!(AccessType::SequentialWrite.is_write());
assert!(AccessType::RandomWrite.is_write());
assert!(!AccessType::SequentialRead.is_write());
assert!(AccessType::SequentialRead.is_sequential());
assert!(AccessType::SequentialWrite.is_sequential());
assert!(!AccessType::RandomRead.is_sequential());
}
#[test]
fn test_storage_tier_latency() {
assert!(
StorageTier::LocalDram.typical_latency_ns() < StorageTier::CxlNear.typical_latency_ns()
);
assert!(
StorageTier::CxlNear.typical_latency_ns() < StorageTier::CxlFar.typical_latency_ns()
);
assert!(StorageTier::CxlFar.typical_latency_ns() < StorageTier::Nvme.typical_latency_ns());
assert!(StorageTier::Nvme.typical_latency_ns() < StorageTier::Hdd.typical_latency_ns());
assert!(StorageTier::Hdd.typical_latency_ns() < StorageTier::Cloud.typical_latency_ns());
}
#[test]
fn test_placement_suggestion() {
let stay = PlacementSuggestion::stay_put();
assert!(!stay.should_migrate());
let migrate = PlacementSuggestion {
tier: StorageTier::LocalDram,
priority: 0.9,
confidence: 0.95,
..Default::default()
};
assert!(migrate.should_migrate());
let low_confidence = PlacementSuggestion {
tier: StorageTier::LocalDram,
priority: 0.9,
confidence: 0.5,
..Default::default()
};
assert!(!low_confidence.should_migrate());
}
#[test]
fn test_gravity_stats() {
let stats = GravityStats {
predictions_correct: 80,
predictions_total: 100,
..Default::default()
};
assert!((stats.accuracy() - 0.8).abs() < 0.01);
}
#[test]
fn test_pi_operation_properties() {
assert!(PiOperation::CompressLz4.writes_data());
assert!(PiOperation::Checksum.reads_data());
assert!(!PiOperation::Checksum.writes_data());
assert!(PiOperation::MemCopy.writes_data());
}
#[test]
fn test_pi_capabilities() {
let caps = PiCapabilities {
checksum: true,
compress_lz4: true,
compress_zstd: false,
..Default::default()
};
assert!(caps.supports(PiOperation::Checksum));
assert!(caps.supports(PiOperation::CompressLz4));
assert!(!caps.supports(PiOperation::CompressZstd));
}
#[test]
fn test_pi_stats() {
let stats = PiStats {
ops_executed: 90,
ops_fallback: 10,
bytes_processed: 1_000_000_000,
execution_time_ns: 1_000_000_000,
..Default::default()
};
assert!((stats.offload_ratio() - 0.9).abs() < 0.01);
assert!((stats.throughput_mbps() - 1000.0).abs() < 1.0);
}
#[test]
fn test_noop_wtemporal_provider() {
let provider = NoOpWTemporalProvider::new();
assert!(provider.record(WTemporalEntry::default()).is_err());
assert!(provider.verify_chain(&WTemporalHash::genesis()).is_err());
assert!(provider.get_entry(&WTemporalHash::genesis()).is_none());
assert!(provider.tip_hash().is_genesis());
}
#[test]
fn test_noop_gravity_provider() {
let provider = NoOpGravityProvider::new();
let mass = provider.calculate_mass(1, &[]);
assert!((mass - 1.0).abs() < 0.01);
let suggestion = provider.suggest_placement(1, 1.0);
assert!(!suggestion.should_migrate());
}
#[test]
fn test_noop_pi_provider() {
let provider = NoOpPiProvider::new();
assert!(!provider.can_offload(PiOperation::Checksum));
assert!(provider.execute(PiOperation::Checksum, 0, 0).is_err());
assert!(!provider.is_available());
let caps = provider.capabilities();
assert!(!caps.checksum);
}
#[test]
fn test_global_providers_fallback() {
let wtemporal = get_wtemporal_provider();
assert!(wtemporal.tip_hash().is_genesis());
let gravity = get_gravity_provider();
let mass = gravity.calculate_mass(0, &[]);
assert!((mass - 1.0).abs() < 0.01);
let pi = get_pi_provider();
assert!(!pi.is_available());
}
#[test]
fn test_convenience_functions() {
assert!(record_operation(WTemporalEntry::default()).is_none());
let mass = calculate_block_mass(0, &[]);
assert!((mass - 1.0).abs() < 0.01);
let suggestion = suggest_block_placement(0, 1.0);
assert!(!suggestion.should_migrate());
assert!(execute_pi_operation(PiOperation::Checksum, 0, 0).is_err());
}
#[test]
fn test_pi_result() {
let success = PiResult::success(PiOperation::Checksum, 12345);
assert!(success.success);
assert_eq!(success.result_value, 12345);
let failure = PiResult::failure(PiOperation::Checksum);
assert!(!failure.success);
}
#[test]
fn test_wtemporal_error_descriptions() {
assert!(!WTemporalError::LedgerFull.description().is_empty());
assert!(!WTemporalError::ChainBroken.description().is_empty());
assert!(!WTemporalError::NotAvailable.description().is_empty());
}
#[test]
fn test_pi_error_descriptions() {
assert!(!PiError::NotSupported.description().is_empty());
assert!(!PiError::NotAvailable.description().is_empty());
assert!(!PiError::HardwareError.description().is_empty());
}
}