Skip to main content

selium_kernel/drivers/
time.rs

1//! Hostcall drivers for time access.
2
3use std::{
4    future::Future,
5    sync::OnceLock,
6    time::{Duration, Instant, SystemTime, UNIX_EPOCH},
7};
8
9use wasmtime::Caller;
10
11use crate::{
12    guest_data::GuestResult,
13    operation::{Contract, Operation},
14    registry::InstanceRegistry,
15};
16use selium_abi::{TimeNow, TimeSleep};
17
18type TimeOps = (
19    std::sync::Arc<Operation<TimeNowDriver>>,
20    std::sync::Arc<Operation<TimeSleepDriver>>,
21);
22
23/// Hostcall driver that returns the current host time.
24pub struct TimeNowDriver;
25/// Hostcall driver that sleeps for the requested duration.
26pub struct TimeSleepDriver;
27
28impl Contract for TimeNowDriver {
29    type Input = ();
30    type Output = TimeNow;
31
32    fn to_future(
33        &self,
34        _caller: &mut Caller<'_, InstanceRegistry>,
35        _input: Self::Input,
36    ) -> impl Future<Output = GuestResult<Self::Output>> + 'static {
37        std::future::ready(Ok(now()))
38    }
39}
40
41impl Contract for TimeSleepDriver {
42    type Input = TimeSleep;
43    type Output = ();
44
45    fn to_future(
46        &self,
47        _caller: &mut Caller<'_, InstanceRegistry>,
48        input: Self::Input,
49    ) -> impl Future<Output = GuestResult<Self::Output>> + 'static {
50        let duration = Duration::from_millis(input.duration_ms);
51        async move {
52            tokio::time::sleep(duration).await;
53            Ok(())
54        }
55    }
56}
57
58fn now() -> TimeNow {
59    TimeNow {
60        unix_ms: unix_ms(),
61        monotonic_ms: monotonic_ms(),
62    }
63}
64
65fn unix_ms() -> u64 {
66    SystemTime::now()
67        .duration_since(UNIX_EPOCH)
68        .unwrap_or_default()
69        .as_millis() as u64
70}
71
72fn monotonic_ms() -> u64 {
73    static START: OnceLock<Instant> = OnceLock::new();
74    START.get_or_init(Instant::now).elapsed().as_millis() as u64
75}
76
77/// Build hostcall operations for time access.
78pub fn operations() -> TimeOps {
79    (
80        Operation::from_hostcall(TimeNowDriver, selium_abi::hostcall_contract!(TIME_NOW)),
81        Operation::from_hostcall(TimeSleepDriver, selium_abi::hostcall_contract!(TIME_SLEEP)),
82    )
83}