Skip to main content

aura_core/effects/
time.rs

1//! Domain-specific time trait definitions (v2).
2//!
3//! These traits correspond to the semantic time types defined in `crate::time`.
4//!
5//! # Effect Classification
6//!
7//! - **Category**: Infrastructure Effect
8//! - **Implementation**: `aura-effects` (Layer 3)
9//! - **Usage**: All crates needing time operations (physical timestamps, logical clocks, ordering tokens)
10//!
11//! This module provides multiple time-related traits:
12//! - `PhysicalTimeEffects`: Wall-clock time for timestamps, expiration, cooldowns
13//! - `LogicalClockEffects`: Vector + Lamport clocks for causal ordering
14//! - `OrderClockEffects`: Privacy-preserving deterministic ordering tokens
15//!
16//! All are infrastructure effects implemented in `aura-effects` with stateless handlers.
17
18use crate::time::{OrderTime, PhysicalTime, TimeOrdering};
19use async_trait::async_trait;
20use serde::{Deserialize, Serialize};
21use uuid::Uuid;
22
23/// Error type for time operations.
24#[derive(Debug, thiserror::Error, Serialize, Deserialize)]
25pub enum TimeError {
26    #[error("Timeout after {timeout_ms}ms")]
27    Timeout { timeout_ms: u64 },
28    #[error("Timeout handle not found: {handle}")]
29    TimeoutNotFound { handle: TimeoutHandle },
30    #[error("Clock sync failed: {reason}")]
31    ClockSyncFailed { reason: String },
32    #[error("Time service unavailable")]
33    ServiceUnavailable,
34    #[error("Operation failed: {reason}")]
35    OperationFailed { reason: String },
36}
37
38/// Handle for timeout operations.
39pub type TimeoutHandle = Uuid;
40
41/// Wake conditions for cooperative scheduling.
42#[derive(Debug, Clone)]
43pub enum WakeCondition {
44    Immediate,
45    NewEvents,
46    EpochReached { target: u64 },
47    TimeoutAt(u64),
48    TimeoutExpired { timeout_id: TimeoutHandle },
49    EventMatching(String),
50    ThresholdEvents { threshold: u32, timeout_ms: u64 },
51    Custom(String),
52}
53
54#[async_trait]
55pub trait PhysicalTimeEffects: Send + Sync {
56    async fn physical_time(&self) -> Result<PhysicalTime, TimeError>;
57    async fn sleep_ms(&self, ms: u64) -> Result<(), TimeError>;
58}
59
60#[async_trait]
61pub trait LogicalClockEffects: Send + Sync {
62    async fn logical_advance(
63        &self,
64        observed: Option<&crate::time::VectorClock>,
65    ) -> Result<crate::time::LogicalTime, TimeError>;
66    async fn logical_now(&self) -> Result<crate::time::LogicalTime, TimeError>;
67}
68
69#[async_trait]
70pub trait OrderClockEffects: Send + Sync {
71    async fn order_time(&self) -> Result<OrderTime, TimeError>;
72}
73
74#[async_trait]
75pub trait TimeComparison: Send + Sync {
76    async fn compare(
77        &self,
78        a: &crate::time::TimeStamp,
79        b: &crate::time::TimeStamp,
80    ) -> Result<TimeOrdering, TimeError>;
81}
82
83/// Convenience trait for common timestamp accessors.
84///
85/// Delegates to `PhysicalTimeEffects` for underlying time operations.
86/// New code should prefer the domain-specific traits above, but this trait
87/// provides helper methods like `current_timestamp()` for simpler use cases.
88#[async_trait]
89pub trait TimeEffects: PhysicalTimeEffects {
90    /// Current Unix timestamp in seconds.
91    async fn current_timestamp(&self) -> u64 {
92        self.physical_time()
93            .await
94            .map(|t| t.ts_ms / 1000)
95            .unwrap_or(0)
96    }
97
98    /// Current Unix timestamp in milliseconds.
99    async fn current_timestamp_ms(&self) -> u64 {
100        self.physical_time().await.map(|t| t.ts_ms).unwrap_or(0)
101    }
102
103    /// Alias for current epoch seconds.
104    async fn current_epoch(&self) -> u64 {
105        self.current_timestamp().await
106    }
107}
108
109/// Blanket implementation for Arc<T> where T: PhysicalTimeEffects
110#[async_trait]
111impl<T: PhysicalTimeEffects + ?Sized> PhysicalTimeEffects for std::sync::Arc<T> {
112    async fn physical_time(&self) -> Result<PhysicalTime, TimeError> {
113        (**self).physical_time().await
114    }
115
116    async fn sleep_ms(&self, ms: u64) -> Result<(), TimeError> {
117        (**self).sleep_ms(ms).await
118    }
119}
120
121/// Blanket implementation for Arc<T> where T: LogicalClockEffects
122#[async_trait]
123impl<T: LogicalClockEffects + ?Sized> LogicalClockEffects for std::sync::Arc<T> {
124    async fn logical_advance(
125        &self,
126        observed: Option<&crate::time::VectorClock>,
127    ) -> Result<crate::time::LogicalTime, TimeError> {
128        (**self).logical_advance(observed).await
129    }
130
131    async fn logical_now(&self) -> Result<crate::time::LogicalTime, TimeError> {
132        (**self).logical_now().await
133    }
134}
135
136/// Blanket implementation for Arc<T> where T: OrderClockEffects
137#[async_trait]
138impl<T: OrderClockEffects + ?Sized> OrderClockEffects for std::sync::Arc<T> {
139    async fn order_time(&self) -> Result<OrderTime, TimeError> {
140        (**self).order_time().await
141    }
142}
143
144/// Blanket implementation for Arc<T> where T: TimeComparison
145#[async_trait]
146impl<T: TimeComparison + ?Sized> TimeComparison for std::sync::Arc<T> {
147    async fn compare(
148        &self,
149        a: &crate::time::TimeStamp,
150        b: &crate::time::TimeStamp,
151    ) -> Result<TimeOrdering, TimeError> {
152        (**self).compare(a, b).await
153    }
154}