use std::{sync::Arc, task::Poll};
use futures::{future::BoxFuture, Future, FutureExt};
use crate::scope::Scope;
pub(crate) struct Body<'scope, 'env: 'scope, R: Send + 'env> {
body_future: Option<BoxFuture<'scope, R>>,
result: Option<R>,
scope: Arc<Scope<'scope, 'env, R>>,
}
impl<'scope, 'env, R> Body<'scope, 'env, R>
where
R: Send,
{
pub(crate) fn new(future: BoxFuture<'scope, R>, scope: Arc<Scope<'scope, 'env, R>>) -> Self {
Self {
body_future: Some(future),
result: None,
scope,
}
}
fn clear(&mut self) {
self.body_future.take();
self.result.take();
self.scope.clear();
}
}
impl<'scope, 'env, R> Drop for Body<'scope, 'env, R>
where
R: Send,
{
fn drop(&mut self) {
self.clear();
}
}
impl<'scope, 'env, R> Future for Body<'scope, 'env, R>
where
R: Send,
{
type Output = R;
fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
if let Some(body_future) = &mut this.body_future {
match body_future.poll_unpin(cx) {
Poll::Ready(r) => {
this.result = Some(r);
this.body_future = None;
}
Poll::Pending => {}
}
}
match ready!(this.scope.poll_jobs(cx)) {
Some(v) => return Poll::Ready(v),
None => match this.result.take() {
None => Poll::Pending,
Some(v) => Poll::Ready(v),
},
}
}
}
impl<R: Send> Unpin for Body<'_, '_, R> {}