wasmx 0.0.0

High-performance, embeddable WebAssembly execution engine
Documentation
#![allow(unused)] // TODO: remove

use core::sync::atomic::Ordering;
use core::time::Duration;

use anyhow::Context as _;
use tokio::time::sleep;
use wasmtime::component::Resource;

use crate::engine::bindings::wasi::clocks::{monotonic_clock, wall_clock};
use crate::engine::wasi::io::Pollable;
use crate::{Ctx, EPOCH_INTERVAL, EPOCH_MONOTONIC_NOW, EPOCH_SYSTEM_NOW};

const NANOS_PER_MILLI: u32 = 1_000_000;

impl wall_clock::Host for Ctx {
    fn now(&mut self) -> wasmtime::Result<wall_clock::Datetime> {
        debug_assert_eq!(EPOCH_INTERVAL, Duration::from_millis(1));

        let now = Duration::from_millis(EPOCH_SYSTEM_NOW.load(Ordering::Relaxed));
        Ok(wall_clock::Datetime {
            seconds: now.as_secs(),
            nanoseconds: now.subsec_nanos(),
        })
    }

    fn resolution(&mut self) -> wasmtime::Result<wall_clock::Datetime> {
        debug_assert_eq!(EPOCH_INTERVAL, Duration::from_millis(1));

        Ok(wall_clock::Datetime {
            seconds: 0,
            nanoseconds: NANOS_PER_MILLI,
        })
    }
}

impl monotonic_clock::Host for Ctx {
    fn now(&mut self) -> wasmtime::Result<monotonic_clock::Instant> {
        debug_assert_eq!(EPOCH_INTERVAL, Duration::from_millis(1));

        let now = EPOCH_MONOTONIC_NOW
            .load(Ordering::Relaxed)
            .saturating_sub(self.clocks.init);
        Ok(now.saturating_mul(NANOS_PER_MILLI.into()))
    }

    fn resolution(&mut self) -> wasmtime::Result<monotonic_clock::Instant> {
        debug_assert_eq!(EPOCH_INTERVAL, Duration::from_millis(1));

        Ok(NANOS_PER_MILLI.into())
    }

    fn subscribe_instant(
        &mut self,
        when: monotonic_clock::Instant,
    ) -> wasmtime::Result<Resource<Pollable>> {
        debug_assert_eq!(EPOCH_INTERVAL, Duration::from_millis(1));

        let when = Duration::from_nanos(when);
        let now = Duration::from_millis(EPOCH_MONOTONIC_NOW.load(Ordering::Relaxed));

        let d = when.saturating_sub(now);
        let p = if !d.is_zero() {
            Pollable::sleep(sleep(d))
        } else {
            Pollable::Ready
        };
        self.table
            .push(p)
            .context("failed to push pollable resource")
    }

    fn subscribe_duration(
        &mut self,
        duration: monotonic_clock::Duration,
    ) -> wasmtime::Result<Resource<Pollable>> {
        let duration = Duration::from_nanos(duration);
        let p = if !duration.is_zero() {
            Pollable::sleep(sleep(duration))
        } else {
            Pollable::Ready
        };
        self.table
            .push(p)
            .context("failed to push pollable resource")
    }
}