use ruin_runtime::{ IntervalHandle, ThreadHandle, clear_interval, current_thread_handle, queue_future, queue_microtask, queue_task, set_interval, set_timeout, spawn_worker, yield_now, }; use std::cell::{Cell, RefCell}; use std::fmt; use std::rc::Rc; use std::sync::OnceLock; use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; static START: OnceLock = OnceLock::new(); static ACTUAL_ORDER: AtomicUsize = AtomicUsize::new(1); macro_rules! log_event { ($expected:literal, $($arg:tt)*) => {{ log_event_impl($expected, format_args!($($arg)*)); }}; } fn log_event_impl(expected: usize, message: fmt::Arguments<'_>) { let actual = ACTUAL_ORDER.fetch_add(1, Ordering::SeqCst); let elapsed = START .get() .expect("showcase start time should be initialized") .elapsed() .as_millis(); println!( "[actual {actual:02} | expected {expected:02} | +{elapsed:04}ms | ts {}] {message}", unix_timestamp_millis(), ); } fn unix_timestamp_millis() -> String { let now = SystemTime::now() .duration_since(UNIX_EPOCH) .expect("system clock should be after the Unix epoch"); format!("{}.{:03}", now.as_secs(), now.subsec_millis()) } fn queue_log(handle: &ThreadHandle, expected: usize, message: impl Into) { let message = message.into(); let queued = handle.queue_task(move || { log_event_impl(expected, format_args!("{message}")); }); assert!(queued, "main thread should accept log task {expected}"); } fn queue_log_microtask(handle: &ThreadHandle, expected: usize, message: impl Into) { let message = message.into(); let queued = handle.queue_task(move || { log_event_impl(expected, format_args!("{message}")); }); assert!(queued, "main thread should accept log microtask {expected}"); } #[ruin_runtime::main] fn main() { START.get_or_init(Instant::now); queue_microtask(|| log_event!(1, "[main] boot microtask: prime UI state")); queue_future(async { log_event!(2, "[main] future: fetch scene metadata"); yield_now().await; log_event!(4, "[main] future: scene metadata cached"); }); queue_microtask(|| { log_event!(3, "[main] microtask queued immediately"); }); let main_handle = current_thread_handle(); queue_task(move || { log_event!( 5, "[main] boot task: paint first frame and start background worker" ); let dashboard_interval = Rc::new(RefCell::new(None::)); let dashboard_ticks = Rc::new(Cell::new(0usize)); { let slot = Rc::clone(&dashboard_interval); let ticks = Rc::clone(&dashboard_ticks); set_dashboard_interval(slot, ticks); } set_timeout(Duration::from_millis(30), || { log_event!(11, "[main] timeout: network snapshot ready"); }); let main_for_worker = main_handle.clone(); let worker = spawn_worker( move || { queue_log( &main_for_worker, 6, "[worker->main] startup task: prepare upload queue", ); { let main_for_microtask = main_for_worker.clone(); queue_microtask(move || { queue_log( &main_for_microtask, 7, "[worker->main] microtask: inspect staging buffers", ); }); } { let main_for_future = main_for_worker.clone(); queue_future(async move { queue_log( &main_for_future, 8, "[worker->main] future: compile shader variants", ); yield_now().await; queue_log( &main_for_future, 9, "[worker->main] future: shader cache is warm", ); }); } { let main_for_task = main_for_worker.clone(); queue_task(move || { queue_log( &main_for_task, 10, "[worker->main] task: upload static geometry", ); }); } let sample_interval = Rc::new(RefCell::new(None::)); let sample_count = Rc::new(Cell::new(0usize)); { let slot = Rc::clone(&sample_interval); let count = Rc::clone(&sample_count); let main_for_samples = main_for_worker.clone(); let handle = set_interval(Duration::from_millis(40), move || { let next = count.get() + 1; count.set(next); queue_log( &main_for_samples, if next == 1 { 12 } else { 17 }, format!("[worker->main] interval: sample batch {next} ready"), ); if next == 2 { let interval = slot.borrow_mut().take().expect("interval should exist"); clear_interval(&interval); queue_log(&main_for_samples, 18, "[worker->main] interval stopped"); } }); *sample_interval.borrow_mut() = Some(handle); } { let main_for_flush = main_for_worker.clone(); set_timeout(Duration::from_millis(110), move || { queue_log_microtask( &main_for_flush, 20, "[worker->main] timeout: flushed final upload batch", ); }); } }, || log_event!(21, "[main] worker exited"), ); set_timeout(Duration::from_millis(70), move || { let queued = worker.queue_task({ let main_from_remote_task = main_handle.clone(); move || { queue_log( &main_from_remote_task, 15, "[worker->main] remote task: upload late texture atlas", ); let main_from_remote_microtask = main_from_remote_task.clone(); queue_microtask(move || { queue_log( &main_from_remote_microtask, 16, "[worker->main] remote microtask: retire staging pages", ); }); } }); log_event!( 14, "[main] timeout: queue late texture upload on worker (queued={queued})" ); }); set_timeout(Duration::from_millis(140), || { log_event!(22, "[main] final timeout: commit frame statistics"); }); }); } fn set_dashboard_interval(slot: Rc>>, ticks: Rc>) { let slot_for_callback = Rc::clone(&slot); let handle = set_interval(Duration::from_millis(50), move || { let next = ticks.get() + 1; ticks.set(next); if next == 1 { log_event!(13, "[main] interval: dashboard tick 1"); return; } let interval = slot_for_callback .borrow_mut() .take() .expect("interval should exist"); clear_interval(&interval); log_event!(19, "[main] interval: dashboard tick 2 and stop"); }); *slot.borrow_mut() = Some(handle); }