|
| 1 | +//! The `#[cxx::bridge]` FFI island for kj-rs-tokio. |
| 2 | +//! |
| 3 | +//! This is the crate's single dedicated FFI-island file (file-top `#![allow(unsafe_code)]`): the |
| 4 | +//! `#[cxx::bridge] mod bridge` is the C++ <-> Rust wire the C++ `kj_rs_tokio::TokioEventPort` |
| 5 | +//! drives (see `tokio-event-port.h`). Everything else -- `lib.rs` and the entire event-port |
| 6 | +//! business logic in `port.rs` -- is wholly-safe, compiler-proven unsafe-free under the crate-root |
| 7 | +//! `#![deny(unsafe_code)]`. |
| 8 | +#![allow(unsafe_code)] |
| 9 | + |
| 10 | +use crate::port::TokioPort; |
| 11 | +use crate::port::new_tokio_port; |
| 12 | + |
| 13 | +#[cxx::bridge(namespace = "kj_rs_tokio")] |
| 14 | +// FFI island: the cxx bridge macro generates the `unsafe` extern shims. |
| 15 | +// unnecessary_box_returns: returning the opaque `TokioPort` to C++ boxed is the cxx idiom. The |
| 16 | +// lint's firing is platform-dependent (it has a size threshold and `TokioPort`'s size differs by |
| 17 | +// target), so `#[expect]` would be unfulfilled on some targets. |
| 18 | +#[expect(clippy::allow_attributes)] |
| 19 | +#[allow(clippy::unnecessary_box_returns)] |
| 20 | +mod bridge { |
| 21 | + // None of these are `Result`: they cannot fail in a way C++ could handle. The panics that CAN |
| 22 | + // occur -- a second port on one thread (`TokioPort::new`), a nested `block_on` from a task |
| 23 | + // that re-entered `promise.wait()` (`wait_*`/`poll`), the LocalSet slot being gone -- are |
| 24 | + // caller-contract violations, and the in-tree cxx fork converts every panic escaping an |
| 25 | + // `extern "Rust"` fn into a `kj::Exception` thrown at the C++ call site. |
| 26 | + extern "Rust" { |
| 27 | + type TokioPort; |
| 28 | + |
| 29 | + fn new_tokio_port() -> Box<TokioPort>; |
| 30 | + |
| 31 | + /// Cancel every task spawned onto this thread's `LocalSet` (dropping their state now, on |
| 32 | + /// this thread). `TokioEventPort`'s destructor calls this before destroying the KJ event |
| 33 | + /// loop and timer it owns, because spawned tasks may own KJ promises. Idempotent. |
| 34 | + fn cancel_spawned_tasks(&self); |
| 35 | + |
| 36 | + /// Block until `wake()` or `notify_kj_service()` is called, running tokio tasks in the |
| 37 | + /// meantime. Returns the wake latch (see `TokioPort::take_wake_latch`). |
| 38 | + fn wait_forever(&self) -> bool; |
| 39 | + |
| 40 | + /// Like `wait_forever`, but additionally returns after `timeout_ns` nanoseconds. The |
| 41 | + /// C++ side computes the timeout from `kj::TimerImpl::timeoutToNextEvent()`. |
| 42 | + fn wait_timeout_ns(&self, timeout_ns: u64) -> bool; |
| 43 | + |
| 44 | + /// Non-blocking: let the tokio scheduler run already-ready tasks for a bounded number of |
| 45 | + /// turns. Never sleeps. Returns the wake latch. |
| 46 | + fn poll(&self) -> bool; |
| 47 | + |
| 48 | + /// Set the wake latch and unblock a concurrent `wait_*`. Callable from any thread. |
| 49 | + fn wake(&self); |
| 50 | + |
| 51 | + /// Loop thread only: KJ has told the port it needs the thread back -- through |
| 52 | + /// `EventPort::setRunnable(true)` (an event was armed) or through the port's |
| 53 | + /// `TimerImpl::SleepHooks` (a sooner timer was armed while sleeping). Unblocks a |
| 54 | + /// concurrent `wait_*` without setting the wake latch; a no-op outside `wait_*`. |
| 55 | + fn notify_kj_service(&self); |
| 56 | + } |
| 57 | +} |
0 commit comments