use core::pin::Pin;
use core::task::{Context, Poll};
use derive_more::Into;
use pin_project_lite::pin_project;
use crate::group::GroupTokenFactory;
use crate::{GroupToken, MonoGroupToken};
pub trait GroupTokenExt<T>: Sized {
#[inline]
fn release_on_ready(self, token: T) -> GroupTokenReleaseOnReady<Self, T> {
GroupTokenReleaseOnReady {
inner: self,
token: Some(token),
}
}
#[inline]
fn release_on_drop(self, token: T) -> GroupTokenReleaseOnDrop<Self, T> {
GroupTokenReleaseOnDrop { inner: self, token }
}
}
pub trait GroupTokenFuncExt<T, Output>: Sized {
fn release_on_return(self, token: T) -> impl FnOnce() -> Output + Send;
}
trait GroupTokenType: Sync + Send + 'static {}
impl GroupTokenType for GroupTokenFactory {}
impl GroupTokenType for GroupToken {}
impl GroupTokenType for MonoGroupToken {}
impl<T: GroupTokenType> GroupTokenType for Option<T> {}
impl<T: GroupTokenType, F: Future> GroupTokenExt<T> for F {}
impl<T: GroupTokenType, Output, F: Send + FnOnce() -> Output> GroupTokenFuncExt<T, Output> for F {
#[inline]
fn release_on_return(self, token: T) -> impl FnOnce() -> Output + Send {
move || {
let res = (self)();
drop(token);
res
}
}
}
pin_project! {
#[derive(Debug, Into)]
pub struct GroupTokenReleaseOnReady<F, T> {
#[pin]
inner: F,
token: Option<T>,
}
}
pin_project! {
#[derive(Debug, Into)]
pub struct GroupTokenReleaseOnDrop<F, T> {
#[pin]
inner: F,
token: T,
}
}
impl<F, T> GroupTokenReleaseOnDrop<F, T> {
#[inline]
pub fn inner_pin(self: Pin<&mut Self>) -> Pin<&mut F> {
self.project().inner
}
#[inline]
pub fn group_token(&self) -> &T {
&self.token
}
}
impl<F, T> GroupTokenReleaseOnReady<F, T> {
#[inline]
pub fn inner_pin(self: Pin<&mut Self>) -> Pin<&mut F> {
self.project().inner
}
#[inline]
pub fn group_token(&self) -> Option<&T> {
self.token.as_ref()
}
}
impl<F: Future, T> Future for GroupTokenReleaseOnDrop<F, T> {
type Output = F::Output;
#[inline]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.inner_pin().poll(cx)
}
}
impl<F: Future, T> Future for GroupTokenReleaseOnReady<F, T> {
type Output = F::Output;
#[inline]
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
let res = this.inner.poll(cx);
if res.is_ready() {
drop(this.token.take());
}
res
}
}