uefi_async/nano_alloc/
control.rs

1
2
3pub mod multiple {
4    pub use futures_concurrency::*;
5}
6
7pub mod single {
8    pub mod join {
9        use core::future::Future;
10        use core::pin::Pin;
11        use core::task::{Context, Poll};
12        use pin_project::pin_project;
13
14        /// Joins multiple futures together, running them concurrently until all complete.
15        ///
16        /// This macro expands to a nested `Join` structure. It does not return any values
17        /// and is intended for tasks that perform side effects (returning `()`).
18        ///
19        /// # Examples
20        /// ```
21        /// join!(task_one(), task_two(), async { do_something().await }).await;
22        /// ```
23        pub use uefi_async_macros::join;
24
25        /// Joins multiple `Result`-returning futures, short-circuiting on the first error.
26        ///
27        /// If any future returns an `Err`, the `try_join!` completes immediately with that error.
28        /// Otherwise, it waits until all tasks complete successfully.
29        ///
30        /// # Examples
31        /// ```
32        /// let result = try_join!(disk_load(), network_fetch()).await;
33        /// if result.is_err() {
34        ///     println!("One of the tasks failed!");
35        /// }
36        /// ```
37        pub use uefi_async_macros::try_join;
38
39        /// Joins multiple futures and collects their results into a flattened tuple.
40        ///
41        /// Unlike `join!`, `join_all!` preserves the output of each future. The macro
42        /// automatically flattens the internal recursive structure so you receive a
43        /// standard tuple of results.
44        ///
45        /// # Examples
46        /// ```
47        /// let (mesh, texture) = join_all!(load_mesh(), load_texture()).await;
48        /// render_engine.draw(mesh, texture);
49        /// ```
50        pub use uefi_async_macros::join_all;
51
52        /// A Future that polls two sub-futures to completion.
53        ///
54        /// This is the primitive building block for the `join!` macro. It stores the completion
55        /// state of two futures and returns `Ready` only when both are done.
56        #[pin_project]
57        pub struct Join<H, T> {
58            #[pin] pub head: H,
59            #[pin] pub tail: T,
60            pub head_done: bool,
61            pub tail_done: bool,
62        }
63
64        impl<H: Future<Output = ()>, T: Future<Output = ()>> Future for Join<H, T> {
65            type Output = ();
66
67            fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
68                let this = self.project();
69
70                if !*this.head_done { *this.head_done = this.head.poll(cx).is_ready() }
71                if !*this.tail_done { *this.tail_done = this.tail.poll(cx).is_ready() }
72                if *this.head_done && *this.tail_done { Poll::Ready(()) } else { Poll::Pending }
73            }
74        }
75
76        /// A Future that polls two `Result`-returning sub-futures with short-circuiting logic.
77        ///
78        /// If either `head` or `tail` returns `Err`, this Future resolves to that `Err` immediately.
79        /// It is the foundation for the `try_join!` macro.
80        #[pin_project]
81        pub struct TryJoin<H, T> {
82            #[pin] pub head: H,
83            #[pin] pub tail: T,
84            pub head_done: bool,
85            pub tail_done: bool,
86        }
87
88        impl<E, H: Future<Output = Result<(),E>>, T: Future<Output = Result<(),E>>> Future for TryJoin<H, T> {
89            type Output = Result<(), E>;
90
91            fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
92                let this = self.project();
93
94                // 1. 轮询第一个任务 (Head)
95                if !*this.head_done {
96                    match this.head.poll(cx) {
97                        Poll::Ready(Err(e)) => return Poll::Ready(Err(e)), // 遇到错误立刻中断
98                        Poll::Ready(Ok(_)) => *this.head_done = true,     // 标记成功
99                        Poll::Pending => {}
100                    }
101                }
102
103                // 2. 轮询第二个任务 (Tail)
104                if !*this.tail_done {
105                    match this.tail.poll(cx) {
106                        Poll::Ready(Err(e)) => return Poll::Ready(Err(e)), // 遇到错误立刻中断
107                        Poll::Ready(Ok(_)) => *this.tail_done = true,     // 标记成功
108                        Poll::Pending => {}
109                    }
110                }
111
112                // 3. 只有当两者都成功时,才返回 Ok
113                if *this.head_done && *this.tail_done { Poll::Ready(Ok(())) } else { Poll::Pending }
114            }
115        }
116
117        /// A Future that polls two sub-futures and stores their outputs.
118        ///
119        /// Once both futures resolve, the outputs are returned as a tuple.
120        #[pin_project]
121        pub struct JoinAll<H: Future, T: Future> {
122            #[pin] pub head: H,
123            #[pin] pub tail: T,
124            pub head_res: Option<H::Output>,
125            pub tail_res: Option<T::Output>,
126        }
127
128        impl<H: Future, T: Future> JoinAll<H, T> {
129            pub fn new(head: H, tail: T) -> Self { Self { head, tail, head_res: None, tail_res: None } }
130        }
131
132        impl<H: Future, T: Future> Future for JoinAll<H, T> {
133            type Output = (H::Output, T::Output);
134            fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
135                let this = self.project();
136
137                if this.head_res.is_none() {
138                    if let Poll::Ready(out) = this.head.poll(cx) {
139                        *this.head_res = Some(out);
140                    }
141                }
142                if this.tail_res.is_none() {
143                    if let Poll::Ready(out) = this.tail.poll(cx) {
144                        *this.tail_res = Some(out);
145                    }
146                }
147
148                if this.head_res.is_some() && this.tail_res.is_some() {
149                    let h = unsafe { this.head_res.take().unwrap_unchecked() };
150                    let t = unsafe { this.tail_res.take().unwrap_unchecked() };
151                    Poll::Ready((h, t))
152                } else {
153                    Poll::Pending
154                }
155            }
156        }
157    }
158}
159