Next Generation WASM Microkernel Operating System
1// Copyright 2025. Jonas Kruckenberg
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use pin_project::pin_project;
9
10use crate::time::{
11 TimeError, Timer,
12 instant::Instant,
13 sleep::{Sleep, sleep, sleep_until},
14};
15use core::{
16 pin::Pin,
17 task::{Context, Poll},
18 time::Duration,
19};
20
21/// Requires a `Future` to complete before the specified duration has elapsed.
22///
23/// # Errors
24///
25/// This function fails for two reasons:
26/// 1. [`TimeError::NoGlobalTimer`] No global timer has been set up yet. Call [`crate::time::set_global_timer`] first.
27/// 2. [`TimeError::DurationTooLong`] The requested deadline lies too far into the future
28pub fn timeout<F>(
29 timer: &Timer,
30 duration: Duration,
31 future: F,
32) -> Result<Timeout<F::IntoFuture>, TimeError>
33where
34 F: IntoFuture,
35{
36 Ok(Timeout {
37 sleep: sleep(timer, duration)?,
38 future: future.into_future(),
39 })
40}
41
42/// Requires a `Future` to complete before the specified deadline has been reached.
43///
44/// # Errors
45///
46/// This function fails for two reasons:
47/// 1. [`TimeError::NoGlobalTimer`] No global timer has been set up yet. Call [`crate::time::set_global_timer`] first.
48/// 2. [`TimeError::DurationTooLong`] The requested deadline lies too far into the future
49pub fn timeout_at<F>(
50 timer: &Timer,
51 deadline: Instant,
52 future: F,
53) -> Result<Timeout<F::IntoFuture>, TimeError>
54where
55 F: IntoFuture,
56{
57 Ok(Timeout {
58 sleep: sleep_until(timer, deadline)?,
59 future: future.into_future(),
60 })
61}
62
63/// Future returned by [`timeout`] and [`timeout_at`].
64#[pin_project]
65#[must_use = "futures do nothing unless `.await`ed or `poll`ed"]
66pub struct Timeout<'timer, F> {
67 #[pin]
68 sleep: Sleep<'timer>,
69 #[pin]
70 future: F,
71}
72
73#[derive(Debug)]
74pub struct Elapsed(());
75
76impl<F> Timeout<'_, F> {
77 /// Gets a reference to the underlying future in this timeout.
78 pub fn get_ref(&self) -> &F {
79 &self.future
80 }
81
82 /// Consumes this timeout, returning the underlying future.
83 pub fn get_mut(&mut self) -> &mut F {
84 &mut self.future
85 }
86
87 /// Consumes this timeout, returning the underlying future.
88 pub fn into_inner(self) -> F {
89 self.future
90 }
91}
92
93impl<F: Future> Future for Timeout<'_, F> {
94 type Output = Result<F::Output, Elapsed>;
95
96 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
97 let me = self.project();
98
99 if let Poll::Ready(v) = me.future.poll(cx) {
100 return Poll::Ready(Ok(v));
101 }
102
103 match me.sleep.poll(cx) {
104 Poll::Ready(()) => Poll::Ready(Err(Elapsed(()))),
105 Poll::Pending => Poll::Pending,
106 }
107 }
108}