Skip to main content

aimdb_core/
context.rs

1//! Runtime context for AimDB services
2//!
3//! Provides a unified interface to runtime capabilities (time, sleep, logging)
4//! as a concrete value wrapping `Arc<dyn RuntimeOps>` — no runtime type
5//! parameter.
6
7use crate::executor::{BoxFuture, LogLevel, RuntimeOps};
8use alloc::sync::Arc;
9
10/// Unified runtime context for AimDB services
11///
12/// Wraps the dyn-safe [`RuntimeOps`] capability surface so services can use
13/// timing and logging without knowing the runtime adapter type. Cheap to
14/// clone (one `Arc`).
15#[derive(Clone)]
16pub struct RuntimeContext {
17    ops: Arc<dyn RuntimeOps>,
18}
19
20impl RuntimeContext {
21    /// Create a new RuntimeContext from the dyn-safe runtime capabilities.
22    pub fn new(ops: Arc<dyn RuntimeOps>) -> Self {
23        Self { ops }
24    }
25
26    /// Access time utilities
27    ///
28    /// Returns a time accessor for clock reads and sleeping.
29    pub fn time(&self) -> Time<'_> {
30        Time { ops: &*self.ops }
31    }
32
33    /// Access logging utilities
34    pub fn log(&self) -> Log<'_> {
35        Log { ops: &*self.ops }
36    }
37
38    /// Direct access to the underlying runtime capabilities.
39    pub fn ops(&self) -> &Arc<dyn RuntimeOps> {
40        &self.ops
41    }
42}
43
44/// Time utilities accessor for RuntimeContext
45///
46/// Durations are plain [`core::time::Duration`]; instants are `u64`
47/// nanoseconds from an arbitrary monotonic epoch (only differences between
48/// two readings are meaningful).
49pub struct Time<'a> {
50    ops: &'a dyn RuntimeOps,
51}
52
53impl Time<'_> {
54    /// Monotonic clock reading in nanoseconds from an arbitrary epoch.
55    ///
56    /// Never decreases; saturates at `u64::MAX` rather than wrapping.
57    pub fn now(&self) -> u64 {
58        self.ops.now_nanos()
59    }
60
61    /// Wall-clock time as `(seconds, nanoseconds)` since the Unix epoch, if
62    /// the runtime has a real-time clock (`None` on e.g. a bare MCU without
63    /// an RTC anchor).
64    pub fn unix_time(&self) -> Option<(u64, u32)> {
65        self.ops.unix_time()
66    }
67
68    /// Completes after at least `duration` has elapsed.
69    ///
70    /// The future is boxed (it crosses the `dyn RuntimeOps` boundary), so each
71    /// call costs one small heap allocation. That is fine for periodic loops
72    /// and timeouts; in a no_std hot path that sleeps every iteration, await
73    /// the adapter's native timer (e.g. `embassy_time::Timer`) directly
74    /// instead.
75    pub fn sleep(&self, duration: core::time::Duration) -> BoxFuture {
76        self.ops.sleep(duration)
77    }
78
79    /// Convenience: sleep for `ms` milliseconds.
80    pub fn sleep_millis(&self, ms: u64) -> BoxFuture {
81        self.ops.sleep(core::time::Duration::from_millis(ms))
82    }
83
84    /// Convenience: sleep for `secs` seconds.
85    pub fn sleep_secs(&self, secs: u64) -> BoxFuture {
86        self.ops.sleep(core::time::Duration::from_secs(secs))
87    }
88}
89
90/// Log utilities accessor for RuntimeContext
91///
92/// Provides structured logging operations.
93pub struct Log<'a> {
94    ops: &'a dyn RuntimeOps,
95}
96
97impl Log<'_> {
98    /// Log an informational message
99    pub fn info(&self, message: &str) {
100        self.ops.log(LogLevel::Info, message)
101    }
102
103    /// Log a debug message
104    pub fn debug(&self, message: &str) {
105        self.ops.log(LogLevel::Debug, message)
106    }
107
108    /// Log a warning message
109    pub fn warn(&self, message: &str) {
110        self.ops.log(LogLevel::Warn, message)
111    }
112
113    /// Log an error message
114    pub fn error(&self, message: &str) {
115        self.ops.log(LogLevel::Error, message)
116    }
117}