1use core::{
2 pin::Pin,
3 task::{Context, Poll},
4};
5
6use derive_more::Into;
7use pin_project_lite::pin_project;
8
9use crate::{GroupToken, MonoGroupToken, group::GroupTokenFactory};
10
11pub trait GroupTokenExt<T>: Sized {
13 #[inline]
15 fn release_on_ready(self, token: T) -> GroupTokenReleaseOnReady<Self, T> {
16 GroupTokenReleaseOnReady {
17 inner: self,
18 token: Some(token),
19 }
20 }
21
22 #[inline]
27 fn release_on_drop(self, token: T) -> GroupTokenReleaseOnDrop<Self, T> {
28 GroupTokenReleaseOnDrop { inner: self, token }
29 }
30}
31
32pub trait GroupTokenFuncExt<T, Output>: Sized {
34 fn release_on_return(self, token: T) -> impl FnOnce() -> Output + Send;
36}
37
38trait GroupTokenType: Sync + Send + 'static {}
39
40impl GroupTokenType for GroupTokenFactory {}
41impl GroupTokenType for GroupToken {}
42impl GroupTokenType for MonoGroupToken {}
43
44impl<T: GroupTokenType, F: Future> GroupTokenExt<T> for F {}
45
46impl<T: GroupTokenType, Output, F: Send + FnOnce() -> Output> GroupTokenFuncExt<T, Output> for F {
47 #[inline]
48 fn release_on_return(self, token: T) -> impl FnOnce() -> Output + Send {
49 move || {
50 let res = (self)();
51 drop(token);
52 res
53 }
54 }
55}
56
57pin_project! {
58 #[derive(Debug, Into)]
62 pub struct GroupTokenReleaseOnReady<F, T> {
63 #[pin]
64 inner: F,
65 token: Option<T>,
66 }
67}
68
69pin_project! {
70 #[derive(Debug, Into)]
74 pub struct GroupTokenReleaseOnDrop<F, T> {
75 #[pin]
76 inner: F,
77 token: T,
78 }
79}
80
81impl<F, T> GroupTokenReleaseOnDrop<F, T> {
82 #[inline]
84 pub fn inner_pin(self: Pin<&mut Self>) -> Pin<&mut F> {
85 self.project().inner
86 }
87
88 #[inline]
90 pub fn group_token(&self) -> &T {
91 &self.token
92 }
93}
94
95impl<F, T> GroupTokenReleaseOnReady<F, T> {
96 #[inline]
98 pub fn inner_pin(self: Pin<&mut Self>) -> Pin<&mut F> {
99 self.project().inner
100 }
101
102 #[inline]
104 pub fn group_token(&self) -> Option<&T> {
105 self.token.as_ref()
106 }
107}
108
109impl<F: Future, T> Future for GroupTokenReleaseOnDrop<F, T> {
110 type Output = F::Output;
111
112 #[inline]
113 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
114 self.inner_pin().poll(cx)
115 }
116}
117
118impl<F: Future, T> Future for GroupTokenReleaseOnReady<F, T> {
119 type Output = F::Output;
120
121 #[inline]
122 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
123 let this = self.project();
124 let res = this.inner.poll(cx);
125 if res.is_ready() {
126 drop(this.token.take());
127 }
128 res
129 }
130}