pub type BoxFuture =
core::pin::Pin<alloc::boxed::Box<dyn core::future::Future<Output = ()> + Send + 'static>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogLevel {
Debug,
Info,
Warn,
Error,
}
pub trait RuntimeOps: Send + Sync {
fn name(&self) -> &'static str;
fn now_nanos(&self) -> u64;
fn unix_time(&self) -> Option<(u64, u32)>;
fn sleep(&self, d: core::time::Duration) -> BoxFuture;
fn log(&self, level: LogLevel, msg: &str);
}
pub type ExecutorResult<T> = Result<T, ExecutorError>;
#[derive(Debug, thiserror::Error)]
pub enum ExecutorError {
#[error("Join queue closed")]
QueueClosed,
}
#[doc(hidden)]
pub mod test_support {
use super::{LogLevel, RuntimeOps};
#[derive(Clone, Copy, Debug, Default)]
pub struct NoopRuntimeOps;
impl RuntimeOps for NoopRuntimeOps {
fn name(&self) -> &'static str {
"noop"
}
fn now_nanos(&self) -> u64 {
0
}
fn unix_time(&self) -> Option<(u64, u32)> {
None
}
fn sleep(&self, _d: core::time::Duration) -> super::BoxFuture {
alloc::boxed::Box::pin(core::future::ready(()))
}
fn log(&self, _level: LogLevel, _msg: &str) {}
}
pub async fn assert_runtime_ops_contract(ops: &dyn RuntimeOps) {
assert!(!ops.name().is_empty(), "name() must be non-empty");
let t0 = ops.now_nanos();
let t1 = ops.now_nanos();
assert!(t1 >= t0, "now_nanos() must be monotonic ({t1} < {t0})");
ops.log(LogLevel::Debug, "runtime-ops contract: debug");
ops.log(LogLevel::Info, "runtime-ops contract: info");
ops.log(LogLevel::Warn, "runtime-ops contract: warn");
ops.log(LogLevel::Error, "runtime-ops contract: error");
ops.sleep(core::time::Duration::ZERO).await;
if let Some((secs, nanos)) = ops.unix_time() {
assert!(
nanos < 1_000_000_000,
"unix_time nanos out of range: {nanos}"
);
assert!(
secs > 1_600_000_000,
"unix_time seconds implausible: {secs}"
);
}
}
}