extern crate alloc;
use super::broadcast_waker;
use crate::{
alloc::{SyncVec, SyncVecError},
sync_types::{self, Lock as _},
};
use core::{cell, convert, marker, pin, sync::atomic, task};
#[cfg(doc)]
use core::future;
pub trait QueuedFuture<T: marker::Send>: marker::Send {
type Output: marker::Send;
type AuxPollData<'a>;
fn poll<'a>(
self: pin::Pin<&mut Self>,
arbitrated_ressource: &mut T,
aux_data: &mut Self::AuxPollData<'a>,
cx: &mut task::Context<'_>,
) -> task::Poll<Self::Output>;
}
#[derive(Clone, Copy, Debug)]
pub enum FutureQueueError {
MemoryAllocationFailure,
}
impl convert::From<broadcast_waker::BroadcastWakerError> for FutureQueueError {
fn from(value: broadcast_waker::BroadcastWakerError) -> Self {
match value {
broadcast_waker::BroadcastWakerError::MemoryAllocationFailure => FutureQueueError::MemoryAllocationFailure,
}
}
}
impl convert::From<SyncVecError> for FutureQueueError {
fn from(value: SyncVecError) -> Self {
match value {
SyncVecError::MemoryAllocationFailure => FutureQueueError::MemoryAllocationFailure,
}
}
}
pub struct FutureQueue<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>> {
wakers: broadcast_waker::BroadcastWakerSubscriptions<ST>,
state: ST::Lock<FutureQueueState<T, F>>,
active_fut: cell::UnsafeCell<Option<F>>,
arbitrated_ressource: cell::UnsafeCell<T>,
}
unsafe impl<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>> marker::Send for FutureQueue<ST, T, F> {}
unsafe impl<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>> marker::Sync for FutureQueue<ST, T, F> {}
impl<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>> FutureQueue<ST, T, F> {
pub fn new(arbitrated_ressource: T) -> Self {
Self {
wakers: broadcast_waker::BroadcastWakerSubscriptions::new(),
state: ST::Lock::from(FutureQueueState::new()),
active_fut: cell::UnsafeCell::new(None),
arbitrated_ressource: cell::UnsafeCell::new(arbitrated_ressource),
}
}
pub fn get_arbitrated_ressource_mut(&mut self) -> &mut T {
self.arbitrated_ressource.get_mut()
}
pub fn enqueue<QP: sync_types::SyncRcPtr<FutureQueue<ST, T, F>>>(
this: pin::Pin<QP>,
fut: F,
) -> Result<EnqueuedFutureSubscription<ST, T, F, QP>, (F, FutureQueueError)> {
let queue_entry_id = match this.wakers.subscribe() {
Ok(queue_entry_id) => queue_entry_id,
Err(e) => return Err((fut, FutureQueueError::from(e))),
};
let state_guard = this.state.lock();
let completion_queue_lock =
sync_types::LockForInner::<'_, _, _, FutureQueueStateDerefInnerCompletionQueueTag>::from_outer(&this.state);
let mut completion_queue_guard =
sync_types::LockForInnerGuard::<'_, _, _, FutureQueueStateDerefInnerCompletionQueueTag>::from_outer(
state_guard,
);
let result;
(completion_queue_guard, result) =
SyncVec::try_reserve_exact(&completion_queue_lock, completion_queue_guard, 1);
if let Err(e) = result {
this.wakers.unsubscribe(queue_entry_id, false);
return Err((fut, FutureQueueError::from(e)));
}
completion_queue_guard.push(None);
let state_guard = completion_queue_guard.into_outer();
let submission_queue_lock =
sync_types::LockForInner::<'_, _, _, FutureQueueStateDerefInnerSubmissionQueueTag>::from_outer(&this.state);
let mut submission_queue_guard =
sync_types::LockForInnerGuard::<'_, _, _, FutureQueueStateDerefInnerSubmissionQueueTag>::from_outer(
state_guard,
);
let result;
(submission_queue_guard, result) =
SyncVec::try_reserve_exact(&submission_queue_lock, submission_queue_guard, 1);
if let Err(e) = result {
let mut state_guard = submission_queue_guard.into_outer();
let popped_cqe = state_guard.completion_queue.pop();
debug_assert!(matches!(popped_cqe, Some(None)));
this.wakers.unsubscribe(queue_entry_id, false);
return Err((fut, FutureQueueError::from(e)));
}
submission_queue_guard.push((queue_entry_id, fut));
drop(submission_queue_guard);
Ok(EnqueuedFutureSubscription::new(this, queue_entry_id))
}
fn cancel_queued(&self, queue_entry_id: broadcast_waker::BroadcastWakerSubscriptionId) {
self.wakers.unsubscribe(queue_entry_id, false);
let mut state_guard = self.state.lock();
if let Some(sqe_index) = state_guard
.submission_queue
.iter()
.position(|sqe| sqe.0 == queue_entry_id)
{
state_guard.submission_queue.remove(sqe_index);
debug_assert!(
!state_guard
.completion_queue
.iter()
.any(|cqe| cqe.as_ref().map(|cqe| cqe.0 == queue_entry_id).unwrap_or(false))
);
let popped_cqe = state_guard.completion_queue.pop();
debug_assert!(matches!(popped_cqe, Some(None)));
} else if state_guard
.active_queue_entry_id
.map(|active_queue_entry_id| active_queue_entry_id == queue_entry_id)
.unwrap_or(false)
{
state_guard.active_queue_entry_id = None;
if state_guard.polling_state == FutureQueuePollingState::Idle {
let active_fut = self.active_fut.get();
let active_fut = unsafe { &mut *active_fut };
*active_fut = None;
}
debug_assert!(
!state_guard
.completion_queue
.iter()
.any(|cqe| cqe.as_ref().map(|cqe| cqe.0 == queue_entry_id).unwrap_or(false))
);
let popped_cqe = state_guard.completion_queue.pop();
debug_assert!(matches!(popped_cqe, Some(None)));
} else {
if let Some(cqe_index) = state_guard
.completion_queue
.iter()
.position(|cqe| cqe.as_ref().map(|cqe| cqe.0 == queue_entry_id).unwrap_or(false))
{
state_guard.completion_queue.remove(cqe_index);
}
}
}
fn poll_from_queue_entry_owner<
'a,
QP: 'a + sync_types::SyncRcPtr<Self>,
QR: 'a + sync_types::SyncRcPtrRef<'a, Self, QP>,
>(
this: pin::Pin<QR>,
queue_entry_id: broadcast_waker::BroadcastWakerSubscriptionId,
aux_poll_data: &mut F::AuxPollData<'_>,
cx: &mut task::Context<'_>,
) -> task::Poll<F::Output>
where
Self: 'a,
{
let this = unsafe { pin::Pin::into_inner_unchecked(this) };
let mut state_guard = this.state.lock();
for (cqe_index, cqe) in state_guard.completion_queue.iter().enumerate() {
match cqe {
Some(cqe) => {
if cqe.0 == queue_entry_id {
let cqe = state_guard.completion_queue.remove(cqe_index).unwrap();
return task::Poll::Ready(cqe.1);
}
}
None => {
break;
}
}
}
this.wakers.set_subscription_waker(queue_entry_id, cx.waker().clone());
let mut wake_gen = this.wakers.wake_gen();
if state_guard.polling_state == FutureQueuePollingState::InPoll {
return task::Poll::Pending;
}
atomic::compiler_fence(atomic::Ordering::Acquire);
let waker = broadcast_waker::BroadcastWakerSubscriptions::waker(&sync_types::SyncRcPtrRefForInner::<
'_,
_,
_,
_,
FutureQueueDerefInnerWakersTag,
>::new(&this));
loop {
let active_fut = this.active_fut.get();
let active_fut = unsafe { &mut *active_fut };
let active_fut_entry = if state_guard.active_queue_entry_id.is_some() {
active_fut.as_mut().unwrap()
} else {
*active_fut = None;
debug_assert!(!state_guard.submission_queue.is_empty());
let head_sqe = state_guard.submission_queue.remove(0);
state_guard.active_queue_entry_id = Some(head_sqe.0);
active_fut.insert(head_sqe.1)
};
let in_poll_guard = FutureQueueInPollGuard::new(&this, state_guard);
let f = unsafe { pin::Pin::new_unchecked(active_fut_entry) };
let arbitrated_ressource = this.arbitrated_ressource.get();
let arbitrated_ressource = unsafe { &mut *arbitrated_ressource };
let result = QueuedFuture::poll(
f,
arbitrated_ressource,
aux_poll_data,
&mut task::Context::from_waker(&waker),
);
state_guard = in_poll_guard.release();
let completed_queue_entry_id = match state_guard.active_queue_entry_id {
Some(active_queue_entry_id) => active_queue_entry_id,
None => {
*active_fut = None;
wake_gen = this.wakers.wake_gen();
continue;
}
};
match result {
task::Poll::Ready(result) => {
state_guard.active_queue_entry_id = None;
*active_fut = None;
if completed_queue_entry_id == queue_entry_id {
let popped_cqe = state_guard.completion_queue.pop();
debug_assert!(matches!(popped_cqe, Some(None)));
drop(state_guard);
this.wakers.unsubscribe(queue_entry_id, true);
return task::Poll::Ready(result);
} else {
let cqe = state_guard
.completion_queue
.iter_mut()
.find(|cqe| cqe.is_none())
.unwrap();
*cqe = Some((completed_queue_entry_id, result));
let completed_waker = this.wakers.unsubscribe(completed_queue_entry_id, false).flatten();
if let Some(completed_waker) = completed_waker {
completed_waker.wake();
}
wake_gen = this.wakers.wake_gen();
}
}
task::Poll::Pending => {
let cur_wake_gen = this.wakers.wake_gen();
if wake_gen != cur_wake_gen {
wake_gen = cur_wake_gen;
} else {
return task::Poll::Pending;
}
}
}
}
}
}
struct FutureQueueDerefInnerWakersTag {}
impl<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>>
sync_types::DerefInnerByTag<FutureQueueDerefInnerWakersTag> for FutureQueue<ST, T, F>
{
crate::impl_deref_inner_by_tag!(wakers, broadcast_waker::BroadcastWakerSubscriptions<ST>);
}
impl<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>>
sync_types::DerefMutInnerByTag<FutureQueueDerefInnerWakersTag> for FutureQueue<ST, T, F>
{
crate::impl_deref_mut_inner_by_tag!(wakers);
}
struct FutureQueueState<T: marker::Send, F: QueuedFuture<T>> {
polling_state: FutureQueuePollingState,
submission_queue: SyncVec<(broadcast_waker::BroadcastWakerSubscriptionId, F)>,
completion_queue: SyncVec<Option<(broadcast_waker::BroadcastWakerSubscriptionId, F::Output)>>,
active_queue_entry_id: Option<broadcast_waker::BroadcastWakerSubscriptionId>,
}
impl<T: marker::Send, F: QueuedFuture<T>> FutureQueueState<T, F> {
fn new() -> Self {
Self {
polling_state: FutureQueuePollingState::Idle,
submission_queue: SyncVec::new(),
completion_queue: SyncVec::new(),
active_queue_entry_id: None,
}
}
}
#[derive(PartialEq, Eq)]
enum FutureQueuePollingState {
Idle,
InPoll,
}
struct FutureQueueInPollGuard<'a, ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>> {
queue: &'a FutureQueue<ST, T, F>,
locked_in_poll: bool,
}
impl<'a, ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>> FutureQueueInPollGuard<'a, ST, T, F> {
fn new<'b>(
queue: &'a FutureQueue<ST, T, F>,
mut state_guard: <ST::Lock<FutureQueueState<T, F>> as sync_types::Lock<FutureQueueState<T, F>>>::Guard<'b>,
) -> Self {
state_guard.polling_state = FutureQueuePollingState::InPoll;
Self {
queue,
locked_in_poll: true,
}
}
fn release(mut self) -> <ST::Lock<FutureQueueState<T, F>> as sync_types::Lock<FutureQueueState<T, F>>>::Guard<'a> {
let mut state_guard = self.queue.state.lock();
state_guard.polling_state = FutureQueuePollingState::Idle;
self.locked_in_poll = false;
state_guard
}
}
impl<'a, ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>> Drop for FutureQueueInPollGuard<'a, ST, T, F> {
fn drop(&mut self) {
if self.locked_in_poll {
self.queue.state.lock().polling_state = FutureQueuePollingState::Idle;
self.locked_in_poll = false;
}
}
}
struct FutureQueueStateDerefInnerSubmissionQueueTag;
impl<T: marker::Send, F: QueuedFuture<T>> sync_types::DerefInnerByTag<FutureQueueStateDerefInnerSubmissionQueueTag>
for FutureQueueState<T, F>
{
crate::impl_deref_inner_by_tag!(
submission_queue,
SyncVec<(broadcast_waker::BroadcastWakerSubscriptionId, F)>
);
}
impl<T: marker::Send, F: QueuedFuture<T>> sync_types::DerefMutInnerByTag<FutureQueueStateDerefInnerSubmissionQueueTag>
for FutureQueueState<T, F>
{
crate::impl_deref_mut_inner_by_tag!(submission_queue);
}
struct FutureQueueStateDerefInnerCompletionQueueTag;
impl<T: marker::Send, F: QueuedFuture<T>> sync_types::DerefInnerByTag<FutureQueueStateDerefInnerCompletionQueueTag>
for FutureQueueState<T, F>
{
crate::impl_deref_inner_by_tag!(
completion_queue,
SyncVec<Option<(broadcast_waker::BroadcastWakerSubscriptionId, F::Output,)>>
);
}
impl<T: marker::Send, F: QueuedFuture<T>> sync_types::DerefMutInnerByTag<FutureQueueStateDerefInnerCompletionQueueTag>
for FutureQueueState<T, F>
{
crate::impl_deref_mut_inner_by_tag!(completion_queue);
}
pub struct EnqueuedFutureSubscription<
ST: sync_types::SyncTypes,
T: marker::Send,
F: QueuedFuture<T>,
QP: sync_types::SyncRcPtr<FutureQueue<ST, T, F>>,
> {
state: EnqueuedFutureSubscriptionState<ST, T, F, QP>,
}
impl<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>, QP: sync_types::SyncRcPtr<FutureQueue<ST, T, F>>>
EnqueuedFutureSubscription<ST, T, F, QP>
{
fn new(queue: pin::Pin<QP>, queue_entry_id: broadcast_waker::BroadcastWakerSubscriptionId) -> Self {
Self {
state: EnqueuedFutureSubscriptionState::Pending {
queue,
queue_entry_id,
_phantom: marker::PhantomData,
},
}
}
pub fn poll(
&mut self,
aux_poll_data: &mut F::AuxPollData<'_>,
cx: &mut task::Context<'_>,
) -> task::Poll<F::Output> {
match &self.state {
EnqueuedFutureSubscriptionState::Pending {
queue,
queue_entry_id,
_phantom,
} => {
let result = FutureQueue::poll_from_queue_entry_owner(
sync_types::SyncRcPtr::as_ref(queue),
*queue_entry_id,
aux_poll_data,
cx,
);
if matches!(result, task::Poll::Ready(_)) {
self.state = EnqueuedFutureSubscriptionState::Done;
}
result
}
EnqueuedFutureSubscriptionState::Done => unreachable!(),
}
}
}
impl<ST: sync_types::SyncTypes, T: marker::Send, F: QueuedFuture<T>, QP: sync_types::SyncRcPtr<FutureQueue<ST, T, F>>>
Drop for EnqueuedFutureSubscription<ST, T, F, QP>
{
fn drop(&mut self) {
match &self.state {
EnqueuedFutureSubscriptionState::Pending {
queue,
queue_entry_id,
_phantom,
} => {
queue.cancel_queued(*queue_entry_id);
self.state = EnqueuedFutureSubscriptionState::Done;
}
EnqueuedFutureSubscriptionState::Done => (),
}
}
}
enum EnqueuedFutureSubscriptionState<
ST: sync_types::SyncTypes,
T: marker::Send,
F: QueuedFuture<T>,
QP: sync_types::SyncRcPtr<FutureQueue<ST, T, F>>,
> {
Pending {
queue: pin::Pin<QP>,
queue_entry_id: broadcast_waker::BroadcastWakerSubscriptionId,
#[allow(clippy::type_complexity)]
_phantom: marker::PhantomData<fn() -> (*const ST, *const T, *const F)>,
},
Done,
}
#[test]
fn test_future_queue_poll_in_order() {
use crate::test::{TestAsyncExecutor, TestNopSyncTypes};
use core::future;
type TestFutureQueueArbitratedRessourceType = u32;
struct TestQueuedFuture {}
impl QueuedFuture<TestFutureQueueArbitratedRessourceType> for TestQueuedFuture {
type Output = u32;
type AuxPollData<'a> = ();
fn poll<'a>(
self: pin::Pin<&mut Self>,
arbitrated_ressource: &mut TestFutureQueueArbitratedRessourceType,
_aux_data: &mut Self::AuxPollData<'a>,
_cx: &mut task::Context<'_>,
) -> task::Poll<Self::Output> {
*arbitrated_ressource += 1;
task::Poll::Ready(*arbitrated_ressource)
}
}
type TestFutureQueue = FutureQueue<TestNopSyncTypes, TestFutureQueueArbitratedRessourceType, TestQueuedFuture>;
type TestFutureQueueSyncRcPtr =
<<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::SyncRcPtr<
TestFutureQueue,
>;
type TestEnqueuedFutureSubscription = EnqueuedFutureSubscription<
TestNopSyncTypes,
TestFutureQueueArbitratedRessourceType,
TestQueuedFuture,
TestFutureQueueSyncRcPtr,
>;
struct TestWrapEnqueuedFuture {
enqueued_future: TestEnqueuedFutureSubscription,
}
impl future::Future for TestWrapEnqueuedFuture {
type Output = <TestQueuedFuture as QueuedFuture<TestFutureQueueArbitratedRessourceType>>::Output;
fn poll(self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
self.get_mut().enqueued_future.poll(&mut (), cx)
}
}
let queue =
<<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::try_new(
FutureQueue::<TestNopSyncTypes, u32, TestQueuedFuture>::new(0),
)
.unwrap();
let queue = unsafe { pin::Pin::new_unchecked(queue) };
let enqueued0 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
.map_err(|(_f, e)| e)
.unwrap();
let enqueued1 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
.map_err(|(_f, e)| e)
.unwrap();
let enqueued2 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
.map_err(|(_f, e)| e)
.unwrap();
let e = TestAsyncExecutor::new();
let w0 = TestAsyncExecutor::spawn(
&e,
TestWrapEnqueuedFuture {
enqueued_future: enqueued0,
},
);
let w1 = TestAsyncExecutor::spawn(
&e,
TestWrapEnqueuedFuture {
enqueued_future: enqueued1,
},
);
let w2 = TestAsyncExecutor::spawn(
&e,
TestWrapEnqueuedFuture {
enqueued_future: enqueued2,
},
);
TestAsyncExecutor::run_to_completion(&e);
assert_eq!(w0.take().unwrap(), 1);
assert_eq!(w1.take().unwrap(), 2);
assert_eq!(w2.take().unwrap(), 3);
}
#[test]
fn test_future_queue_poll_in_reverse_order() {
use crate::test::{TestAsyncExecutor, TestNopSyncTypes};
use core::future;
type TestFutureQueueArbitratedRessourceType = u32;
struct TestQueuedFuture {}
impl QueuedFuture<TestFutureQueueArbitratedRessourceType> for TestQueuedFuture {
type Output = u32;
type AuxPollData<'a> = ();
fn poll<'a>(
self: pin::Pin<&mut Self>,
arbitrated_ressource: &mut TestFutureQueueArbitratedRessourceType,
_aux_data: &mut Self::AuxPollData<'a>,
_cx: &mut task::Context<'_>,
) -> task::Poll<Self::Output> {
*arbitrated_ressource += 1;
task::Poll::Ready(*arbitrated_ressource)
}
}
type TestFutureQueue = FutureQueue<TestNopSyncTypes, TestFutureQueueArbitratedRessourceType, TestQueuedFuture>;
type TestFutureQueueSyncRcPtr =
<<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::SyncRcPtr<
TestFutureQueue,
>;
type TestEnqueuedFutureSubscription = EnqueuedFutureSubscription<
TestNopSyncTypes,
TestFutureQueueArbitratedRessourceType,
TestQueuedFuture,
TestFutureQueueSyncRcPtr,
>;
struct TestWrapEnqueuedFuture {
enqueued_future: TestEnqueuedFutureSubscription,
}
impl future::Future for TestWrapEnqueuedFuture {
type Output = <TestQueuedFuture as QueuedFuture<TestFutureQueueArbitratedRessourceType>>::Output;
fn poll(self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<Self::Output> {
self.get_mut().enqueued_future.poll(&mut (), cx)
}
}
let queue =
<<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::try_new(
FutureQueue::<TestNopSyncTypes, u32, TestQueuedFuture>::new(0),
)
.unwrap();
let queue = unsafe { pin::Pin::new_unchecked(queue) };
let enqueued0 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
.map_err(|(_f, e)| e)
.unwrap();
let enqueued1 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
.map_err(|(_f, e)| e)
.unwrap();
let enqueued2 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
.map_err(|(_f, e)| e)
.unwrap();
let e = TestAsyncExecutor::new();
let w2 = TestAsyncExecutor::spawn(
&e,
TestWrapEnqueuedFuture {
enqueued_future: enqueued2,
},
);
TestAsyncExecutor::run_to_completion(&e);
assert_eq!(w2.take().unwrap(), 3);
let w1 = TestAsyncExecutor::spawn(
&e,
TestWrapEnqueuedFuture {
enqueued_future: enqueued1,
},
);
TestAsyncExecutor::run_to_completion(&e);
assert_eq!(w1.take().unwrap(), 2);
let w0 = TestAsyncExecutor::spawn(
&e,
TestWrapEnqueuedFuture {
enqueued_future: enqueued0,
},
);
TestAsyncExecutor::run_to_completion(&e);
assert_eq!(w0.take().unwrap(), 1);
}
#[test]
fn test_future_queue_cancel_queued() {
use crate::test::{TestAsyncExecutor, TestNopSyncTypes};
use core::future;
type TestFutureQueueArbitratedRessourceType = u32;
struct TestQueuedFuture {}
impl QueuedFuture<TestFutureQueueArbitratedRessourceType> for TestQueuedFuture {
type Output = u32;
type AuxPollData<'a> = ();
fn poll<'a>(
self: pin::Pin<&mut Self>,
arbitrated_ressource: &mut TestFutureQueueArbitratedRessourceType,
_aux_data: &mut Self::AuxPollData<'a>,
_cx: &mut task::Context<'_>,
) -> task::Poll<Self::Output> {
*arbitrated_ressource += 1;
task::Poll::Ready(*arbitrated_ressource)
}
}
type TestFutureQueue = FutureQueue<TestNopSyncTypes, TestFutureQueueArbitratedRessourceType, TestQueuedFuture>;
type TestFutureQueueSyncRcPtr =
<<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::SyncRcPtr<
TestFutureQueue,
>;
type TestEnqueuedFutureSubscription = EnqueuedFutureSubscription<
TestNopSyncTypes,
TestFutureQueueArbitratedRessourceType,
TestQueuedFuture,
TestFutureQueueSyncRcPtr,
>;
struct TestCancelQueuedFuture {
enqueued0: TestEnqueuedFutureSubscription,
enqueued1: Option<TestEnqueuedFutureSubscription>,
enqueued2: TestEnqueuedFutureSubscription,
}
impl future::Future for TestCancelQueuedFuture {
type Output = ();
fn poll(self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<()> {
let this = self.get_mut();
drop(this.enqueued1.take());
assert_eq!(this.enqueued2.poll(&mut (), cx), task::Poll::Ready(2));
assert_eq!(this.enqueued0.poll(&mut (), cx), task::Poll::Ready(1));
task::Poll::Ready(())
}
}
let queue =
<<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::try_new(
FutureQueue::<TestNopSyncTypes, u32, TestQueuedFuture>::new(0),
)
.unwrap();
let queue = unsafe { pin::Pin::new_unchecked(queue) };
let enqueued0 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
.map_err(|(_f, e)| e)
.unwrap();
let enqueued1 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
.map_err(|(_f, e)| e)
.unwrap();
let enqueued2 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture {})
.map_err(|(_f, e)| e)
.unwrap();
let e = TestAsyncExecutor::new();
let w = TestAsyncExecutor::spawn(
&e,
TestCancelQueuedFuture {
enqueued0,
enqueued1: Some(enqueued1),
enqueued2,
},
);
TestAsyncExecutor::run_to_completion(&e);
w.take().unwrap();
}
#[test]
fn test_future_queue_cancel_active() {
use crate::test::{TestAsyncExecutor, TestNopSyncTypes};
use core::future;
type TestFutureQueueArbitratedRessourceType = u32;
struct TestQueuedFuture {
stall_forever: bool,
}
impl QueuedFuture<TestFutureQueueArbitratedRessourceType> for TestQueuedFuture {
type Output = u32;
type AuxPollData<'a> = ();
fn poll<'a>(
self: pin::Pin<&mut Self>,
arbitrated_ressource: &mut TestFutureQueueArbitratedRessourceType,
_aux_data: &mut Self::AuxPollData<'a>,
_cx: &mut task::Context<'_>,
) -> task::Poll<Self::Output> {
if self.stall_forever {
return task::Poll::Pending;
}
*arbitrated_ressource += 1;
task::Poll::Ready(*arbitrated_ressource)
}
}
type TestFutureQueue = FutureQueue<TestNopSyncTypes, TestFutureQueueArbitratedRessourceType, TestQueuedFuture>;
type TestFutureQueueSyncRcPtr =
<<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::SyncRcPtr<
TestFutureQueue,
>;
type TestEnqueuedFutureSubscription = EnqueuedFutureSubscription<
TestNopSyncTypes,
TestFutureQueueArbitratedRessourceType,
TestQueuedFuture,
TestFutureQueueSyncRcPtr,
>;
struct TestCancelQueuedFuture {
enqueued0: Option<TestEnqueuedFutureSubscription>,
enqueued1: TestEnqueuedFutureSubscription,
enqueued2: TestEnqueuedFutureSubscription,
}
impl future::Future for TestCancelQueuedFuture {
type Output = ();
fn poll(self: pin::Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<()> {
let this = self.get_mut();
assert_eq!(this.enqueued0.as_mut().unwrap().poll(&mut (), cx), task::Poll::Pending);
assert_eq!(this.enqueued1.poll(&mut (), cx), task::Poll::Pending);
assert_eq!(this.enqueued2.poll(&mut (), cx), task::Poll::Pending);
drop(this.enqueued0.take());
assert_eq!(this.enqueued2.poll(&mut (), cx), task::Poll::Ready(2));
assert_eq!(this.enqueued1.poll(&mut (), cx), task::Poll::Ready(1));
task::Poll::Ready(())
}
}
let queue =
<<TestNopSyncTypes as sync_types::SyncTypes>::SyncRcPtrFactory as sync_types::SyncRcPtrFactory>::try_new(
FutureQueue::<TestNopSyncTypes, u32, TestQueuedFuture>::new(0),
)
.unwrap();
let queue = unsafe { pin::Pin::new_unchecked(queue) };
let enqueued0 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture { stall_forever: true })
.map_err(|(_f, e)| e)
.unwrap();
let enqueued1 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture { stall_forever: false })
.map_err(|(_f, e)| e)
.unwrap();
let enqueued2 = FutureQueue::enqueue(queue.clone(), TestQueuedFuture { stall_forever: false })
.map_err(|(_f, e)| e)
.unwrap();
let e = TestAsyncExecutor::new();
let w = TestAsyncExecutor::spawn(
&e,
TestCancelQueuedFuture {
enqueued0: Some(enqueued0),
enqueued1,
enqueued2,
},
);
TestAsyncExecutor::run_to_completion(&e);
w.take().unwrap();
}