use super::*;
use crate::DynExecutor;
use crate::thread_executor::thread_executor;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_lite::wasm_lite_test)]
fn test_is_objsafe() {
#[allow(unused)]
fn is_objsafe(_obj: &DynExecutor) {}
}
#[derive(Debug, Clone)]
struct RecordingExecutor(Arc<AtomicUsize>);
impl SomeExecutor for RecordingExecutor {
type ExecutorNotifier = Infallible;
fn spawn<F: Future + Send + 'static, Notifier: ObserverNotified<F::Output> + Send>(
&mut self,
_task: Task<F, Notifier>,
) -> impl Observer<Value = F::Output> + Send
where
Self: Sized,
F::Output: Send + Unpin,
{
#[allow(unreachable_code)]
{
unimplemented!() as TypedObserver<F::Output, Infallible>
}
}
#[allow(clippy::manual_async_fn)]
fn spawn_async<'s, F: Future + Send + 'static, Notifier: ObserverNotified<F::Output> + Send>(
&'s mut self,
_task: Task<F, Notifier>,
) -> impl Future<Output = impl Observer<Value = F::Output>> + Send + 's
where
Self: Sized,
F::Output: Send + Unpin,
{
#[allow(unreachable_code)]
#[allow(clippy::async_yields_async)]
async {
unimplemented!() as TypedObserver<F::Output, Infallible>
}
}
fn spawn_objsafe(&mut self, _task: ObjSafeTask) -> BoxedSendObserver {
unimplemented!()
}
fn spawn_objsafe_async<'s>(&'s mut self, _task: ObjSafeTask) -> BoxedSendObserverFuture<'s> {
unimplemented!()
}
fn clone_box(&self) -> Box<DynExecutor> {
Box::new(self.clone())
}
fn executor_notifier(&mut self) -> Option<Self::ExecutorNotifier> {
None
}
fn block_on_objsafe(&mut self, future: BoxedBlockOnFuture<'_>) -> Box<dyn Any + Send> {
self.0.fetch_add(1, Ordering::Relaxed);
crate::block_on(future)
}
}
impl SomeExecutorExt for RecordingExecutor {}
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_lite::wasm_lite_test(worker))]
fn block_on_returns_the_output() {
let mut executor = crate::last_resort::LastResortExecutor::new();
assert_eq!(executor.block_on(async { 6 * 7 }), 42);
}
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_lite::wasm_lite_test(worker))]
fn block_on_installs_itself_and_then_restores() {
let before = thread_executor(|e| e.is_some());
let mut executor = crate::last_resort::LastResortExecutor::new();
let visible = executor.block_on(async { thread_executor(|e| e.is_some()) });
assert!(visible, "the executor should be current inside the block");
assert_eq!(
thread_executor(|e| e.is_some()),
before,
"the previous thread executor should be back afterwards"
);
}
#[cfg(not(target_arch = "wasm32"))]
#[test]
fn block_on_restores_the_thread_executor_after_a_panic() {
let before = thread_executor(|e| e.is_some());
let result = std::panic::catch_unwind(|| {
let mut executor = crate::last_resort::LastResortExecutor::new();
executor.block_on(async { panic!("boom") })
});
assert!(result.is_err());
assert_eq!(thread_executor(|e| e.is_some()), before);
}
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_lite::wasm_lite_test(worker))]
fn block_on_through_a_box_reaches_the_underlying_override() {
let calls = Arc::new(AtomicUsize::new(0));
let mut boxed: Box<DynExecutor> = Box::new(RecordingExecutor(calls.clone()));
assert_eq!(boxed.block_on(async { "hello" }), "hello");
assert_eq!(calls.load(Ordering::Relaxed), 1);
}
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_lite::wasm_lite_test(worker))]
fn block_on_objsafe_erases_and_downcasts() {
let calls = Arc::new(AtomicUsize::new(0));
let mut executor = RecordingExecutor(calls.clone());
let erased: BoxedBlockOnFuture<'_> = Box::pin(async { Box::new(7u32) as Box<dyn Any + Send> });
let out = executor.block_on_objsafe(erased);
assert_eq!(*out.downcast::<u32>().expect("wrong type"), 7);
assert_eq!(calls.load(Ordering::Relaxed), 1);
}