aimdb_core/
time.rs

1//! Time and timing utilities for AimDB
2//!
3//! This module provides time-related traits and utilities for runtime adapters,
4//! including timestamping, delays, and scheduling operations.
5
6use core::future::Future;
7
8/// Trait for adapters that provide current time information
9///
10/// Enables timing information for timestamping, performance measurement, and scheduling.
11pub trait TimestampProvider {
12    /// Type representing an instant in time for this runtime
13    type Instant;
14
15    /// Gets the current timestamp according to the runtime's time source
16    ///
17    /// # Example
18    /// ```rust,no_run
19    /// use aimdb_core::time::TimestampProvider;
20    ///
21    /// fn log_operation<T: TimestampProvider>(provider: &T) {
22    ///     let _timestamp = provider.now();
23    ///     println!("Operation completed");
24    /// }
25    /// ```
26    fn now(&self) -> Self::Instant;
27}
28
29/// Trait for adapters that support sleep/delay operations
30///
31/// Provides capability to pause execution for a specified duration.
32pub trait SleepCapable {
33    /// Type representing a duration for this runtime
34    type Duration;
35
36    /// Pauses execution for the specified duration without blocking other tasks
37    ///
38    /// # Example
39    /// ```rust,no_run
40    /// use aimdb_core::time::SleepCapable;
41    /// use std::time::Duration;
42    ///
43    /// async fn rate_limited_operation<S: SleepCapable<Duration = Duration>>(
44    ///     sleeper: &S
45    /// ) {
46    ///     println!("Starting operation...");
47    ///     sleeper.sleep(Duration::from_secs(1)).await;
48    ///     println!("Operation completed after delay");
49    /// }
50    /// ```
51    fn sleep(&self, duration: Self::Duration) -> impl Future<Output = ()> + Send;
52}
53
54/// Utility functions for time-based operations
55pub mod utils {
56    use super::*;
57
58    /// Measures the execution time of an async operation
59    ///
60    /// Works in both `std` and `no_std` environments using the provided `TimestampProvider`.
61    pub async fn measure_async<F, T, P>(provider: &P, operation: F) -> (T, P::Instant, P::Instant)
62    where
63        F: Future<Output = T>,
64        P: TimestampProvider,
65    {
66        let start = provider.now();
67        let result = operation.await;
68        let end = provider.now();
69        (result, start, end)
70    }
71
72    /// Creates a generic timeout error for operations that exceed their time limit
73    pub fn create_timeout_error(_operation_name: &str) -> crate::DbError {
74        crate::DbError::ConnectionFailed {
75            #[cfg(feature = "std")]
76            endpoint: "timeout".to_string(),
77            #[cfg(feature = "std")]
78            reason: format!("{} operation timed out", _operation_name),
79            #[cfg(not(feature = "std"))]
80            _endpoint: (),
81            #[cfg(not(feature = "std"))]
82            _reason: (),
83        }
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[cfg(feature = "std")]
92    mod std_tests {
93        use super::*;
94        use std::time::Instant;
95
96        // Mock providers for testing
97        struct MockTimestampProvider;
98
99        impl TimestampProvider for MockTimestampProvider {
100            type Instant = Instant;
101
102            fn now(&self) -> Self::Instant {
103                Instant::now()
104            }
105        }
106
107        #[test]
108        fn test_timestamp_provider_trait() {
109            let provider = MockTimestampProvider;
110            let timestamp1 = provider.now();
111
112            // Timestamps should be valid Instant values
113            let timestamp2 = provider.now();
114
115            // Second timestamp should be greater than or equal to first
116            assert!(timestamp2 >= timestamp1);
117        }
118
119        #[test]
120        fn test_timeout_error_creation() {
121            let error = utils::create_timeout_error("database query");
122
123            // Test error format for std feature
124            #[cfg(feature = "std")]
125            {
126                let error_string = format!("{}", error);
127                assert!(error_string.contains("database query operation timed out"));
128            }
129        }
130
131        #[test]
132        fn test_measure_async_trait_based() {
133            let provider = MockTimestampProvider;
134
135            // Test that we can measure with the trait-based approach
136            let runtime = tokio::runtime::Runtime::new().unwrap();
137            let (result, start, end) = runtime.block_on(utils::measure_async(&provider, async {
138                // Simulate work with a small computation
139                let mut sum = 0;
140                for i in 0..1000 {
141                    sum += i;
142                }
143                sum
144            }));
145
146            assert_eq!(result, 499500); // Sum of 0..1000
147                                        // End time should be greater than or equal to start time
148            assert!(end >= start);
149        }
150    }
151
152    #[cfg(not(feature = "std"))]
153    mod no_std_tests {
154        use super::{utils, TimestampProvider};
155
156        // Mock timestamp provider for no_std testing
157        struct MockNoStdTimestampProvider {
158            counter: core::sync::atomic::AtomicU64,
159        }
160
161        impl MockNoStdTimestampProvider {
162            fn new() -> Self {
163                Self {
164                    counter: core::sync::atomic::AtomicU64::new(0),
165                }
166            }
167        }
168
169        impl TimestampProvider for MockNoStdTimestampProvider {
170            type Instant = u64;
171
172            fn now(&self) -> Self::Instant {
173                self.counter
174                    .fetch_add(1, core::sync::atomic::Ordering::Relaxed)
175            }
176        }
177
178        #[test]
179        fn test_timeout_error_creation_no_std() {
180            let _error = utils::create_timeout_error("operation");
181            // In no_std mode, we just verify the error can be created
182            // without panicking
183        }
184
185        #[test]
186        fn test_measure_async_no_std() {
187            // Test that measure_async works in no_std with a simple timestamp provider
188            let provider = MockNoStdTimestampProvider::new();
189
190            // Since we can't use tokio in no_std, we'll test the function signature
191            // and basic functionality without actually running async code
192            let future = async {
193                // Simulate some work
194                42
195            };
196
197            // This mainly tests that the function compiles and accepts the right types
198            // We explicitly drop the future since we can't await it in no_std tests
199            core::mem::drop(utils::measure_async(&provider, future));
200        }
201    }
202}