luminal/runtime/join_handle.rs
1//! Join handle implementation
2//!
3//! This module provides the implementation of `JoinHandle`,
4//! which is used to await the completion of async tasks.
5
6use std::future::Future;
7use std::pin::Pin;
8use std::task::{Context, Poll};
9use crossbeam_channel::{Receiver, TryRecvError};
10
11use super::task::TaskId;
12
13/// Handle for awaiting the completion of an asynchronous task
14///
15/// Similar to tokio's JoinHandle, this allows waiting for a task to complete
16/// and retrieving its result. It implements `Future` so it can be awaited
17/// in async contexts.
18///
19/// # Type Parameters
20///
21/// * `T` - The output type of the task
22///
23/// # Examples
24///
25/// ```
26/// use luminal::Runtime;
27///
28/// let rt = Runtime::new().unwrap();
29/// let handle = rt.spawn(async { 42 });
30///
31/// // Await the handle
32/// let result = rt.block_on(async {
33/// handle.await
34/// });
35/// assert_eq!(result, 42);
36/// ```
37pub struct JoinHandle<T> {
38 /// The unique identifier of the task
39 #[allow(dead_code)]
40 pub(crate) id: TaskId,
41
42 /// Channel for receiving the task's result when it completes
43 pub(crate) receiver: Receiver<T>,
44}
45
46impl<T: Send + 'static> Future for JoinHandle<T> {
47 type Output = T;
48
49 /// Poll method implementation for JoinHandle
50 ///
51 /// This checks if the result is ready by attempting to receive
52 /// from the channel. If the result is available, it's returned as Ready.
53 /// If not, it returns Pending to be polled again later.
54 ///
55 /// # Parameters
56 ///
57 /// * `self` - Pinned mutable reference to self
58 /// * `_cx` - Context for the poll (not used in this implementation)
59 ///
60 /// # Returns
61 ///
62 /// `Poll::Ready(T)` when the task completes, or `Poll::Pending` if still running
63 fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
64 match self.receiver.try_recv() {
65 Ok(result) => Poll::Ready(result),
66 Err(TryRecvError::Empty) => Poll::Pending,
67 Err(TryRecvError::Disconnected) => {
68 // Channel disconnected - likely due to panic or dropped task
69 // For safety we could abort, but that would break API
70 // Instead log warning and return a default/placeholder
71 eprintln!("WARNING: Task channel disconnected unexpectedly");
72 // Keep pending to allow task completion or timeout
73 Poll::Pending
74 },
75 }
76 }
77}