pub mod time {
pub use std::time::Duration;
#[cfg(all(feature = "simulation", madsim))]
pub use madsim::time::{
Instant, Interval, MissedTickBehavior, Sleep, error, interval, interval_at, sleep,
sleep_until, timeout,
};
#[cfg(not(all(feature = "simulation", madsim)))]
pub use tokio::time::{
Instant, Interval, MissedTickBehavior, Sleep, error, interval, interval_at, sleep,
sleep_until, timeout,
};
}
pub mod task {
#[cfg(all(feature = "simulation", madsim))]
pub use madsim::task::{JoinHandle, spawn, spawn_local, yield_now};
#[cfg(not(all(feature = "simulation", madsim)))]
pub use tokio::task::{JoinHandle, spawn, spawn_local, yield_now};
}
pub mod runtime {
#[cfg(not(all(feature = "simulation", madsim)))]
pub use tokio::runtime::{Builder, Handle, Runtime};
#[cfg(all(feature = "simulation", madsim))]
mod sim {
use std::io;
#[derive(Debug)]
pub struct Builder {
_inner: (),
}
impl Builder {
#[must_use]
pub fn new_current_thread() -> Self {
Self { _inner: () }
}
#[must_use]
pub fn new_multi_thread() -> Self {
Self { _inner: () }
}
#[must_use]
pub fn worker_threads(&mut self, _val: usize) -> &mut Self {
self
}
#[must_use]
pub fn thread_name(&mut self, _val: impl Into<String>) -> &mut Self {
self
}
#[must_use]
pub fn enable_all(&mut self) -> &mut Self {
self
}
pub fn build(&mut self) -> io::Result<madsim::runtime::Runtime> {
Ok(madsim::runtime::Runtime::new())
}
}
pub use madsim::runtime::Handle;
pub type Runtime = madsim::runtime::Runtime;
}
#[cfg(all(feature = "simulation", madsim))]
pub use sim::{Builder, Handle, Runtime};
}
pub mod signal {
#[cfg(all(feature = "simulation", madsim))]
pub use madsim::signal::ctrl_c;
#[cfg(not(all(feature = "simulation", madsim)))]
pub use tokio::signal::ctrl_c;
}
#[allow(unused_imports)]
mod surface {
use super::{
runtime::{Builder, Handle, Runtime},
signal::ctrl_c,
task::{JoinHandle, spawn, spawn_local, yield_now},
time::{
Duration, Instant, Interval, MissedTickBehavior, Sleep, error, interval, interval_at,
sleep, sleep_until, timeout,
},
};
const _: fn(Duration) -> Sleep = sleep;
const _: fn(Instant) -> Sleep = sleep_until;
const _: fn(Duration) -> Interval = interval;
const _: fn(Instant, Duration) -> Interval = interval_at;
}
#[cfg(test)]
mod tests {
#[cfg(all(feature = "simulation", madsim))]
use nautilus_core::{datetime::NANOSECONDS_IN_SECOND, time::nanos_since_unix_epoch};
use rstest::rstest;
use super::*;
#[cfg(not(all(feature = "simulation", madsim)))]
#[tokio::test]
async fn test_dst_sleep() {
let start = time::Instant::now();
time::sleep(time::Duration::from_millis(10)).await;
let elapsed = start.elapsed();
assert!(elapsed >= time::Duration::from_millis(5));
}
#[cfg(not(all(feature = "simulation", madsim)))]
#[tokio::test]
async fn test_dst_task_spawn() {
let handle = task::spawn(async { 42 });
let result = handle.await.unwrap();
assert_eq!(result, 42);
}
#[cfg(not(all(feature = "simulation", madsim)))]
#[tokio::test]
async fn test_real_tokio_sync_alongside_dst() {
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
tx.send(7).unwrap();
let result = time::timeout(time::Duration::from_secs(1), rx.recv()).await;
assert_eq!(result.unwrap(), Some(7));
}
#[cfg(not(all(feature = "simulation", madsim)))]
#[rstest]
fn test_dst_runtime_builder() {
let rt = runtime::Builder::new_multi_thread()
.worker_threads(2)
.enable_all()
.build()
.unwrap();
let result = rt.block_on(async { 99 });
assert_eq!(result, 99);
}
#[cfg(all(feature = "simulation", madsim))]
#[madsim::test]
async fn test_dst_sleep() {
let start = time::Instant::now();
time::sleep(time::Duration::from_millis(100)).await;
let elapsed = start.elapsed();
assert!(elapsed >= time::Duration::from_millis(100));
assert!(elapsed < time::Duration::from_millis(101));
}
#[cfg(all(feature = "simulation", madsim))]
#[madsim::test]
async fn test_dst_task_spawn() {
let handle = task::spawn(async { 42 });
let result = handle.await.unwrap();
assert_eq!(result, 42);
}
#[cfg(all(feature = "simulation", madsim))]
#[madsim::test]
async fn test_real_tokio_sync_alongside_dst() {
let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel();
tx.send(7).unwrap();
let result = time::timeout(time::Duration::from_secs(1), rx.recv()).await;
assert_eq!(result.unwrap(), Some(7));
}
#[cfg(all(feature = "simulation", madsim))]
#[rstest]
fn test_dst_runtime_builder() {
let rt = runtime::Builder::new_multi_thread()
.worker_threads(2)
.enable_all()
.build()
.unwrap();
let result = rt.block_on(async { 99 });
assert_eq!(result, 99);
}
#[cfg(all(feature = "simulation", madsim))]
#[madsim::test]
async fn test_dst_wall_clock_advances_with_virtual_time() {
let before = nanos_since_unix_epoch();
time::sleep(time::Duration::from_secs(60)).await;
let after = nanos_since_unix_epoch();
let elapsed_ns = after.saturating_sub(before);
let sixty_seconds_ns = 60 * NANOSECONDS_IN_SECOND;
assert!(
elapsed_ns >= sixty_seconds_ns,
"wall clock did not advance by full virtual sleep: elapsed={elapsed_ns}ns"
);
}
}