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}