Skip to main content

kozan_scheduler/
lib.rs

1//! `kozan-scheduler` — Task scheduler and async executor for Kozan.
2//!
3//! Like Chrome's `base/task/` + `blink/platform/scheduler/`.
4//! Standalone crate — zero dependency on `kozan-core`.
5//!
6//! # Architecture
7//!
8//! ```text
9//! Scheduler (MainThreadScheduler — the event loop)
10//! ├── TaskQueueManager (SequenceManager — priority picker)
11//! │   └── TaskQueue × 6 (one per priority level)
12//! ├── MicrotaskQueue (drain after each macrotask)
13//! ├── LocalExecutor (!Send async runtime)
14//! ├── FrameScheduler (vsync-driven frame timing)
15//! └── WakeReceiver (cross-thread task delivery)
16//! ```
17//!
18//! # Event loop algorithm (HTML spec)
19//!
20//! ```text
21//! loop {
22//!     1. Receive cross-thread tasks
23//!     2. Promote delayed tasks
24//!     3. Poll async executor
25//!     4. Pick ONE macrotask → run
26//!     5. Drain ALL microtasks
27//!     6. If frame due → callbacks → style → layout → paint
28//!     7. Park until next event
29//! }
30//! ```
31
32pub mod executor;
33pub mod frame;
34pub mod microtask;
35pub mod queue;
36pub mod scheduler;
37pub mod task;
38pub mod timer;
39pub mod waker;
40
41// Re-exports: the main types users need.
42pub use executor::{LocalExecutor, TaskId};
43pub use frame::{FrameInfo, FrameScheduler, FrameTiming};
44pub use microtask::{Microtask, MicrotaskQueue};
45pub use queue::{TaskQueue, TaskQueueManager};
46pub use scheduler::{Scheduler, TickResult};
47pub use task::{Task, TaskPriority};
48pub use waker::{CrossThreadTask, SendError, WakeReceiver, WakeSender, cross_thread_channel};
49
50// ---- Compile-time Send/Sync guarantees ----
51//
52// These assertions prevent accidental breakage of threading contracts.
53// A refactor that removes PhantomData or changes a field type will
54// fail to compile here — not silently at runtime.
55
56#[cfg(test)]
57mod send_sync_tests {
58    use super::*;
59
60    // Must be Send + Clone (shared across background threads).
61    const _: fn() = || {
62        fn assert_send_clone<T: Send + Clone>() {}
63        assert_send_clone::<WakeSender>();
64    };
65
66    // Must be Send (crosses thread boundary).
67    const _: fn() = || {
68        fn assert_send<T: Send>() {}
69        assert_send::<CrossThreadTask>();
70    };
71
72    // Must NOT be Send (stays on window thread).
73    // Scheduler contains WakeReceiver which has PhantomData<*const ()>.
74    // If this compiles, our !Send guarantee is broken.
75    // We verify !Send via a negative test that would fail to compile
76    // if Scheduler were Send. Unfortunately Rust doesn't have
77    // static_assert_not_impl, so we test this at runtime:
78    #[test]
79    fn send_types_are_send() {
80        fn assert_send<T: Send>() {}
81        assert_send::<WakeSender>();
82        assert_send::<CrossThreadTask>();
83    }
84}