use std::future::Future;
use crate::{Promise, PromiseRejection};
impl<T, E> Promise<T, E>
where
T: Send + 'static,
E: PromiseRejection,
{
pub fn eager(future: impl Future<Output = Result<T, E>> + Send + 'static) -> Self {
#[cfg(all(feature = "tokio", feature = "smol"))]
return if tokio::runtime::Handle::try_current().is_ok() {
Self::eager_with_tokio(future)
} else {
Self::eager_with_smol(future)
};
#[cfg(all(feature = "tokio", not(feature = "smol")))]
return if tokio::runtime::Handle::try_current().is_ok() {
Self::eager_with_tokio(future)
} else {
Self::lazy(future)
};
#[cfg(all(feature = "smol", not(feature = "tokio")))]
return Self::eager_with_smol(future);
}
}
#[cfg(test)]
#[allow(clippy::expect_used)]
mod tests {
use crate::{Promise, PromiseRejection, TaskFailure};
#[derive(Debug)]
#[allow(dead_code)]
enum E {
AlreadyConsumed,
TaskFailed(TaskFailure),
}
impl PromiseRejection for E {
fn already_consumed() -> Self {
Self::AlreadyConsumed
}
fn task_failed(failure: TaskFailure) -> Self {
Self::TaskFailed(failure)
}
}
#[cfg(all(feature = "tokio", not(feature = "smol")))]
#[test]
fn falls_back_to_lazy_outside_runtime_context() {
use std::task::{Context, Waker};
let mut promise: Promise<i32, E> = Promise::eager(async { Ok(42) });
assert!(promise.is_pending());
promise.poll(&mut Context::from_waker(Waker::noop()));
match promise.consume() {
Some(Ok(v)) => assert_eq!(v, 42),
other => panic!("expected Resolved(42), got {other:?}"),
}
}
#[cfg(feature = "tokio")]
#[test]
fn resolves_value_via_tokio() {
let rt = tokio::runtime::Builder::new_current_thread()
.build()
.expect("build current-thread tokio runtime");
let result = rt.block_on(async { Promise::<i32, E>::eager(async { Ok(42) }).await });
assert!(matches!(result, Ok(42)));
}
#[cfg(all(feature = "smol", not(feature = "tokio")))]
#[test]
fn resolves_value_via_smol() {
let result = smol::block_on(async { Promise::<i32, E>::eager(async { Ok(42) }).await });
assert!(matches!(result, Ok(42)));
}
}