Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at */
extern crate nsstring;
use cstr::cstr;
use nsstring::*;
use std::cell::RefCell;
use std::future::Future;
use xpcom::{interfaces::nsIThreadManager, xpcom, xpcom_method};
#[xpcom(implement(nsINestedEventLoopCondition), nonatomic)]
struct FutureCompleteCondition<T: 'static> {
value: RefCell<Option<T>>,
impl<T: 'static> FutureCompleteCondition<T> {
xpcom_method!(is_done => IsDone() -> bool);
fn is_done(&self) -> Result<bool, nsresult> {
/// Spin the event loop on the current thread until `future` is resolved.
/// # Safety
/// Spinning a nested event loop should always be avoided when possible, as it
/// can cause hangs, break JS run-to-completion guarantees, and break other C++
/// code currently on the stack relying on heap invariants. While in a pure-rust
/// codebase this method would only be ill-advised and not technically "unsafe",
/// it is marked as unsafe due to the potential for triggering unsafety in
/// unrelated C++ code.
pub unsafe fn spin_event_loop_until<F>(
reason: &'static str,
future: F,
) -> Result<F::Output, nsresult>
F: Future + 'static,
F::Output: 'static,
let thread_manager =
let cond = FutureCompleteCondition::<F::Output>::allocate(InitFutureCompleteCondition {
value: RefCell::new(None),
// Spawn our future onto the current thread event loop, and record the
// completed value as it completes.
let cond2 = cond.clone();
crate::spawn_local(reason, async move {
let rv = future.await;
*cond2.value.borrow_mut() = Some(rv);
.SpinEventLoopUntil(&*nsCStr::from(reason), cond.coerce())
let rv = cond.value.borrow_mut().take();