#[cfg(all(test, feature = "std"))]
use crate::sync::{Arc, Mutex};
#[cfg(test)]
use alloc::boxed::Box;
#[cfg(all(test, not(feature = "std")))]
use alloc::rc::Rc;
#[cfg(all(test, not(feature = "std")))]
use core::cell::RefCell;
#[cfg(test)]
use core::convert::Infallible;
use core::future::Future;
#[cfg(test)]
use core::pin::Pin;
#[cfg(test)]
use core::task::{Context, Poll};
pub trait FutureSpawner: MaybeSend + MaybeSync + 'static {
type E;
type SpawnedFutureResult<O>: Future<Output = Result<O, Self::E>> + Unpin;
fn spawn<O: MaybeSend + 'static, T: Future<Output = O> + MaybeSend + 'static>(
&self, future: T,
) -> Self::SpawnedFutureResult<O>;
}
#[cfg(test)]
trait MaybeSendableFuture: Future<Output = ()> + MaybeSend + 'static {}
#[cfg(test)]
impl<F: Future<Output = ()> + MaybeSend + 'static> MaybeSendableFuture for F {}
#[cfg(feature = "std")]
pub use core::marker::Sync as MaybeSync;
#[cfg(not(feature = "std"))]
pub trait MaybeSync {}
#[cfg(not(feature = "std"))]
impl<T> MaybeSync for T where T: ?Sized {}
#[cfg(feature = "std")]
pub use core::marker::Send as MaybeSend;
#[cfg(not(feature = "std"))]
pub trait MaybeSend {}
#[cfg(not(feature = "std"))]
impl<T> MaybeSend for T where T: ?Sized {}
#[cfg(all(test, feature = "std"))]
pub(crate) struct FutureQueue(Mutex<Vec<Pin<Box<dyn MaybeSendableFuture>>>>);
#[cfg(all(test, not(feature = "std")))]
pub(crate) struct FutureQueue(RefCell<Vec<Pin<Box<dyn MaybeSendableFuture>>>>);
#[cfg(all(test, feature = "std"))]
pub struct FutureQueueCompletion<O>(Arc<Mutex<Option<O>>>);
#[cfg(all(test, not(feature = "std")))]
pub struct FutureQueueCompletion<O>(Rc<RefCell<Option<O>>>);
#[cfg(all(test, feature = "std"))]
impl<O> FutureQueueCompletion<O> {
fn new() -> Self {
Self(Arc::new(Mutex::new(None)))
}
fn complete(&self, o: O) {
*self.0.lock().unwrap() = Some(o);
}
}
#[cfg(all(test, feature = "std"))]
impl<O> Clone for FutureQueueCompletion<O> {
fn clone(&self) -> Self {
#[cfg(all(test, feature = "std"))]
{
Self(Arc::clone(&self.0))
}
#[cfg(all(test, not(feature = "std")))]
{
Self(Rc::clone(&self.0))
}
}
}
#[cfg(all(test, not(feature = "std")))]
impl<O> FutureQueueCompletion<O> {
fn new() -> Self {
Self(Rc::new(RefCell::new(None)))
}
fn complete(&self, o: O) {
*self.0.borrow_mut() = Some(o);
}
}
#[cfg(all(test, not(feature = "std")))]
impl<O> Clone for FutureQueueCompletion<O> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
#[cfg(all(test, feature = "std"))]
impl<O> Future for FutureQueueCompletion<O> {
type Output = Result<O, Infallible>;
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<O, Infallible>> {
match Pin::into_inner(self).0.lock().unwrap().take() {
None => Poll::Pending,
Some(o) => Poll::Ready(Ok(o)),
}
}
}
#[cfg(all(test, not(feature = "std")))]
impl<O> Future for FutureQueueCompletion<O> {
type Output = Result<O, Infallible>;
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Result<O, Infallible>> {
match Pin::into_inner(self).0.borrow_mut().take() {
None => Poll::Pending,
Some(o) => Poll::Ready(Ok(o)),
}
}
}
#[cfg(test)]
impl FutureQueue {
pub(crate) fn new() -> Self {
#[cfg(feature = "std")]
{
FutureQueue(Mutex::new(Vec::new()))
}
#[cfg(not(feature = "std"))]
{
FutureQueue(RefCell::new(Vec::new()))
}
}
pub(crate) fn pending_futures(&self) -> usize {
#[cfg(feature = "std")]
{
self.0.lock().unwrap().len()
}
#[cfg(not(feature = "std"))]
{
self.0.borrow().len()
}
}
pub(crate) fn poll_futures(&self) {
let mut futures;
#[cfg(feature = "std")]
{
futures = self.0.lock().unwrap();
}
#[cfg(not(feature = "std"))]
{
futures = self.0.borrow_mut();
}
futures.retain_mut(|fut| {
let waker = crate::util::async_poll::dummy_waker();
match fut.as_mut().poll(&mut Context::from_waker(&waker)) {
Poll::Ready(()) => false,
Poll::Pending => true,
}
});
}
}
#[cfg(test)]
impl FutureSpawner for FutureQueue {
type E = Infallible;
type SpawnedFutureResult<O> = FutureQueueCompletion<O>;
fn spawn<O: MaybeSend + 'static, F: Future<Output = O> + MaybeSend + 'static>(
&self, f: F,
) -> FutureQueueCompletion<O> {
let completion = FutureQueueCompletion::new();
let compl_ref = completion.clone();
let future = async move {
compl_ref.complete(f.await);
};
#[cfg(feature = "std")]
{
self.0.lock().unwrap().push(Box::pin(future));
}
#[cfg(not(feature = "std"))]
{
self.0.borrow_mut().push(Box::pin(future));
}
completion
}
}
#[cfg(test)]
impl<D: core::ops::Deref<Target = FutureQueue> + MaybeSend + MaybeSync + 'static> FutureSpawner
for D
{
type E = Infallible;
type SpawnedFutureResult<O> = FutureQueueCompletion<O>;
fn spawn<O: MaybeSend + 'static, F: Future<Output = O> + MaybeSend + 'static>(
&self, f: F,
) -> FutureQueueCompletion<O> {
let completion = FutureQueueCompletion::new();
let compl_ref = completion.clone();
let future = async move {
compl_ref.complete(f.await);
};
#[cfg(feature = "std")]
{
self.0.lock().unwrap().push(Box::pin(future));
}
#[cfg(not(feature = "std"))]
{
self.0.borrow_mut().push(Box::pin(future));
}
completion
}
}