1use alloc::boxed::Box;
16
17use core::future::Future;
18use core::pin::Pin;
19use core::ptr;
20use core::task::{Context, Poll};
21
22use futures::future::{BoxFuture, LocalBoxFuture};
23use futures::ready;
24use futures_util::future::{join, Join};
25use paste::paste;
26use pin_project_lite::pin_project;
27
28use crate::Async;
29
30pub trait Assignable<T> {
35 fn from(value: T) -> Self;
37}
38
39impl<'a, T, Fut: Future<Output = T> + Send + 'a> Assignable<Fut> for BoxFuture<'a, T> {
40 fn from(future: Fut) -> Self {
42 Box::pin(future)
43 }
44}
45
46impl<'a, T, Fut: Future<Output = T> + 'a> Assignable<Fut> for LocalBoxFuture<'a, T> {
47 fn from(future: Fut) -> Self {
49 Box::pin(future)
50 }
51}
52
53pub trait Unary<Operand> {
58 type Output;
60
61 fn op(operand: Operand) -> Self::Output;
63}
64
65pub trait Binary<Lhs, Rhs> {
72 type Output;
74
75 fn op(lhs: Lhs, rhs: Rhs) -> Self::Output;
77
78 fn op_assign(lhs: &mut Lhs, rhs: Rhs)
81 where
82 Lhs: Assignable<Self::Output>,
83 {
84 unsafe {
85 let this = ptr::read(lhs);
86 ptr::write(lhs, Lhs::from(Self::op(this, rhs)))
87 }
88 }
89}
90
91macro_rules! from_std_unary_ops {
92 ($($Op:ident),*) => {$(
93 paste! {
94 #[doc = concat!(
95 "Returns a [`Future`] that will resolve the given `Future` ",
96 "and [`", stringify!([<$Op:lower>]), "`]",
97 "(core::ops::", stringify!($Op), "::", stringify!([<$Op:lower>]), ") ",
98 "its result.\n\n# Example\n\n",
99 "```rust\n",
100 "use futures_executor::block_on;\n",
101 "use async_ops::", stringify!([<$Op:lower>]), ";\n\n",
102 "let a = async { 42 };\n\n",
103 "let result = async {\n",
104 " ", stringify!([<$Op:lower>]),"(a).await\n",
105 "};\n\n",
106 "assert_eq!(std::ops::", stringify!($Op), "::",
107 stringify!([<$Op:lower>]), "(42), block_on(result));")]
108 pub fn [<$Op:lower>]<Operand: core::ops::$Op>(
109 operand: impl Future<Output = Operand>,
110 ) -> impl Future<Output = Operand::Output> {
111 $Op::op(operand)
112 }
113
114 pin_project! {
115 #[doc = concat!(
116 "A [`Future`] that will resolve a `Future` and ",
117 "[`", stringify!([<$Op:lower>]), "`]",
118 "(core::ops::", stringify!($Op), "::", stringify!([<$Op:lower>]),
119 ") its result.")]
120 #[must_use = "futures do nothing unless you `.await` or poll them"]
121 pub struct [<Async $Op>]<Operand: Future> {
122 #[pin]
123 operand: Operand
124 }
125 }
126
127 impl<Operand: Future> Future for [<Async $Op>]<Operand>
128 where
129 Operand::Output: core::ops::$Op,
130 {
131 type Output = <Operand::Output as core::ops::$Op>::Output;
132
133 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
134 let operand = ready!(self.project().operand.poll(cx));
135 Poll::Ready(core::ops::$Op::[<$Op:lower>](operand))
136 }
137 }
138
139 #[doc = concat!(
140 "A [`Unary`] operation that will concurrently resolve a [`Future`] ",
141 "and [`", stringify!([<$Op:lower>]), "`]",
142 "(core::ops::", stringify!($Op), "::", stringify!([<$Op:lower>]), ") ",
143 "its result.\n\n# Example\n\n",
144 "```rust\n",
145 "use futures_executor::block_on;\n",
146 "use async_ops::", stringify!($Op), ";\n\n",
147 "let a = async { 42 };\n\n",
148 "let result = async {\n",
149 " async_ops::on(a).unary_op(", stringify!($Op),").await\n",
150 "};\n\n",
151 "assert_eq!(std::ops::", stringify!($Op), "::",
152 stringify!([<$Op:lower>]), "(42), block_on(result));")]
153 pub struct $Op;
154
155 impl<Operand: Future> Unary<Operand> for $Op
156 where
157 Operand::Output: core::ops::$Op,
158 {
159 type Output = [<Async $Op>]<Operand>;
160
161 fn op(operand: Operand) -> Self::Output {
162 [<Async $Op>] { operand }
163 }
164 }
165
166 impl<Operand: Future> core::ops::$Op for Async<Operand>
167 where
168 Operand::Output: core::ops::$Op,
169 {
170 type Output = Async<[<Async $Op>]<Operand>>;
171
172 fn [<$Op:lower>](self) -> Self::Output {
173 crate::on($Op::op(self.future))
174 }
175 }
176 }
177 )*};
178}
179
180macro_rules! from_std_binary_ops {
181 ($($Op:ident),*) => {$(
182 paste! {
183 #[doc = concat!(
184 "Returns a [`Future`] that will concurrently resolve given `Futures` ",
185 "and [`", stringify!([<$Op:lower>]), "`]",
186 "(core::ops::", stringify!($Op), "::", stringify!([<$Op:lower>]), ") ",
187 "their results.\n\n# Example\n\n",
188 "```rust\n",
189 "use futures_executor::block_on;\n",
190 "use async_ops::", stringify!([<$Op:lower>]), ";\n\n",
191 "let a = async { 42 };\n",
192 "let b = async { 2 };\n\n",
193 "let result = async {\n",
194 " ", stringify!([<$Op:lower>]),"(a, b).await\n",
195 "};\n\n",
196 "assert_eq!(std::ops::", stringify!($Op), "::",
197 stringify!([<$Op:lower>]), "(42, 2), block_on(result));")]
198 pub fn [<$Op:lower>]<Lhs: core::ops::$Op<Rhs>, Rhs>(
199 lhs: impl Future<Output = Lhs>,
200 rhs: impl Future<Output = Rhs>,
201 ) -> impl Future<Output = Lhs::Output> {
202 $Op::op(lhs, rhs)
203 }
204
205 pin_project! {
206 #[doc = concat!(
207 "A [`Future`] that will concurrently resolve two `Futures` and ",
208 "[`", stringify!([<$Op:lower>]), "`]",
209 "(core::ops::", stringify!($Op), "::", stringify!([<$Op:lower>]),
210 ") their results.")]
211 #[must_use = "futures do nothing unless you `.await` or poll them"]
212 pub struct [<Async $Op>]<Lhs: Future, Rhs: Future> {
213 #[pin]
214 future: Join<Lhs, Rhs>
215 }
216 }
217
218 impl<Lhs: Future, Rhs: Future> Future for [<Async $Op>]<Lhs, Rhs>
219 where
220 Lhs::Output: core::ops::$Op<Rhs::Output>,
221 {
222 type Output = <Lhs::Output as core::ops::$Op<Rhs::Output>>::Output;
223
224 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
225 let (lhs, rhs) = ready!(self.project().future.poll(cx));
226 Poll::Ready(core::ops::$Op::[<$Op:lower>](lhs, rhs))
227 }
228 }
229
230 #[doc = concat!(
231 "A [`Binary`] operation that will concurrently resolve two ",
232 "[`Futures`](Future) and [`", stringify!([<$Op:lower>]), "`]",
233 "(core::ops::", stringify!($Op), "::", stringify!([<$Op:lower>]), ") ",
234 "their results.\n\n# Example\n\n",
235 "```rust\n",
236 "use futures_executor::block_on;\n",
237 "use async_ops::", stringify!($Op), ";\n\n",
238 "let a = async { 42 };\n",
239 "let b = async { 2 };\n\n",
240 "let result = async {\n",
241 " async_ops::on(a).op(", stringify!($Op),", b).await\n",
242 "};\n\n",
243 "assert_eq!(std::ops::", stringify!($Op), "::",
244 stringify!([<$Op:lower>]), "(42, 2), block_on(result));")]
245 pub struct $Op;
246
247 impl<Lhs: Future, Rhs: Future> Binary<Lhs, Rhs> for $Op
248 where
249 Lhs::Output: core::ops::$Op<Rhs::Output>,
250 {
251 type Output = [<Async $Op>]<Lhs, Rhs>;
252
253 fn op(lhs: Lhs, rhs: Rhs) -> Self::Output {
254 [<Async $Op>] {
255 future: join(lhs, rhs),
256 }
257 }
258 }
259
260 impl<Lhs: Future, Rhs: Future> core::ops::$Op<Rhs> for Async<Lhs>
261 where
262 Lhs::Output: core::ops::$Op<Rhs::Output>,
263 {
264 type Output = Async<[<Async $Op>]<Lhs, Rhs>>;
265
266 fn [<$Op:lower>](self, rhs: Rhs) -> Self::Output {
267 crate::on($Op::op(self.future, rhs))
268 }
269 }
270
271 impl<Lhs, Rhs> core::ops::[<$Op Assign>]<Rhs> for Async<Lhs>
272 where
273 Lhs: Assignable<[<Async $Op>]<Lhs, Rhs>> + Future,
274 Rhs: Future,
275 <Lhs as Future>::Output: core::ops::$Op<Rhs::Output>,
276 {
277 fn [<$Op:lower _assign>](&mut self, rhs: Rhs) {
278 $Op::op_assign(&mut self.future, rhs);
279 }
280 }
281 }
282 )*};
283}
284
285from_std_unary_ops!(Neg, Not);
286from_std_binary_ops!(Add, BitAnd, BitOr, BitXor, Div, Mul, Rem, Shl, Shr, Sub);
287
288#[cfg(test)]
289mod tests {
290 use super::*;
291
292 use core::future::ready;
293
294 use futures_executor::block_on;
295
296 struct ReturnRhs;
297
298 impl<Lhs, Rhs> Binary<Lhs, Rhs> for ReturnRhs {
299 type Output = Rhs;
300
301 fn op(_: Lhs, rhs: Rhs) -> Self::Output {
302 rhs
303 }
304 }
305
306 #[test]
307 fn box_future_op_assign() {
308 let mut future: BoxFuture<usize> = Assignable::from(ready(2));
309
310 ReturnRhs::op_assign(&mut future, ready(42));
311
312 assert_eq!(42, block_on(future));
313 }
314
315 #[test]
316 fn local_box_future_op_assign() {
317 let mut future: LocalBoxFuture<usize> = Assignable::from(ready(2));
318
319 ReturnRhs::op_assign(&mut future, ready(42));
320
321 assert_eq!(42, block_on(future));
322 }
323}