C/C++ API Reference
Loading...
Searching...
No Matches
future_timeout.h
1// Copyright 2025 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <functional>
17#include <optional>
18#include <type_traits>
19#include <utility>
20
21#include "lib/stdcompat/type_traits.h"
22#include "pw_assert/assert.h"
23#include "pw_async2/channel.h"
24#include "pw_async2/context.h"
25#include "pw_async2/future.h"
26#include "pw_async2/poll.h"
27#include "pw_async2/system_time_provider.h"
28#include "pw_async2/time_provider.h"
29#include "pw_async2/value_future.h"
30#include "pw_chrono/system_clock.h"
31#include "pw_function/function.h"
32#include "pw_preprocessor/compiler.h"
33#include "pw_status/status.h"
34
35namespace pw::async2 {
36
38
42 using value_type = void;
43 constexpr Poll<> operator()() const { return Ready(); }
44};
45
52template <typename T>
54 using value_type = T;
55
57 constexpr ReadyFunctionResultResolution() = default;
58
59 constexpr explicit ReadyFunctionResultResolution(
60 pw::Function<T()> ready_value_fn)
61 : ready_(std::move(ready_value_fn)) {}
62
63 constexpr Poll<T> operator()() const {
64 return Ready<T>(std::in_place_t{}, ready_());
65 }
66
67 private:
68 pw::Function<T()> ready_;
69};
70
80template <typename T, typename ConstantType, typename CastType = T>
82 using value_type = T;
83 constexpr ReadyConstantValueResolution() = default;
84 constexpr explicit ReadyConstantValueResolution(
85 const cpp20::remove_cvref_t<ConstantType>& value)
86 : constant_(value) {}
87 constexpr explicit ReadyConstantValueResolution(
88 cpp20::remove_cvref_t<ConstantType>&& value)
89 : constant_(std::move(value)) {}
90
91 constexpr Poll<T> operator()() const {
92 return Ready<T>(std::in_place_t{}, CastType(constant_));
93 }
94
95 private:
96 cpp20::remove_cvref_t<ConstantType> constant_;
97};
98
104template <typename T>
106 T,
107 std::integral_constant<pw::Status::Code, PW_STATUS_DEADLINE_EXCEEDED>,
108 pw::Status>;
109
129template <
130 typename T,
131 typename PrimaryFuture,
132 typename TimeoutFuture,
133 typename TimeoutResolution,
134 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>,
135 typename = std::enable_if_t<!std::is_lvalue_reference_v<TimeoutFuture>>,
136 typename = std::enable_if_t<!std::is_lvalue_reference_v<TimeoutResolution>>>
137class [[nodiscard]] FutureWithTimeout {
138 static_assert(
140 "FutureWithTimeout can only be used when PrimaryFuture is a Future type");
141 static_assert(
143 "FutureWithTimeout can only be used when TimeoutFuture is a Future type");
144
145 public:
146 using value_type = T;
147
148 constexpr FutureWithTimeout() = default;
149
150 FutureWithTimeout(PrimaryFuture&& primary_future,
151 TimeoutFuture&& timeout_future,
152 TimeoutResolution&& timeout_resolution)
153 : primary_future_(std::move(primary_future)),
154 timeout_future_(std::move(timeout_future)),
155 timeout_resolution_(std::move(timeout_resolution)),
156 state_(FutureState::kPending) {}
157
158 [[nodiscard]] constexpr bool is_pendable() const {
159 return state_.is_pendable();
160 }
161
162 [[nodiscard]] constexpr bool is_complete() const {
163 return state_.is_complete();
164 }
165
166 Poll<value_type> Pend(Context& cx) {
167 PW_ASSERT(is_pendable());
168 auto result = primary_future_.Pend(cx);
169 if (result.IsReady()) {
170 state_.MarkComplete();
171 return Ready<value_type>(std::in_place, std::move(result).value());
172 }
173
174 if (timeout_future_.Pend(cx).IsReady()) {
175 state_.MarkComplete();
176 return timeout_resolution_();
177 }
178
179 return Pending();
180 }
181
182 private:
183 PrimaryFuture primary_future_;
184 TimeoutFuture timeout_future_;
185 PW_NO_UNIQUE_ADDRESS TimeoutResolution timeout_resolution_;
186 FutureState state_;
187};
188
196template <typename T,
197 typename PrimaryFuture,
198 typename TimeoutFuture,
199 typename TimeoutResolution>
200auto CreateFutureWithTimeout(PrimaryFuture&& primary_future,
201 TimeoutFuture&& timeout_future,
202 TimeoutResolution&& timeout_resolution)
204 std::decay_t<PrimaryFuture>,
205 std::decay_t<TimeoutFuture>,
206 std::decay_t<TimeoutResolution>> {
207 return FutureWithTimeout<T,
208 std::decay_t<PrimaryFuture>,
209 std::decay_t<TimeoutFuture>,
210 std::decay_t<TimeoutResolution>>(
211 std::forward<PrimaryFuture>(primary_future),
212 std::forward<TimeoutFuture>(timeout_future),
213 std::forward<TimeoutResolution>(timeout_resolution));
214}
215
226template <
227 typename PrimaryFuture,
228 typename TimeProvider,
229 typename Duration,
230 int&... kExplicitGuard,
231 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
232auto Timeout(PrimaryFuture&& primary_future,
233 TimeProvider& time_provider,
234 Duration delay) {
236 return CreateFutureWithTimeout<ResultType>(
237 std::forward<PrimaryFuture>(primary_future),
238 time_provider.WaitFor(delay),
240}
241
253template <
254 typename PrimaryFuture,
255 int&... kExplicitGuard,
256 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
257auto Timeout(PrimaryFuture&& primary_future,
258 typename chrono::SystemClock::duration delay) {
260 return CreateFutureWithTimeout<ResultType>(
261 std::forward<PrimaryFuture>(primary_future),
262 GetSystemTimeProvider().WaitFor(delay),
264}
265
277template <typename Clock>
278void TimeoutOr([[maybe_unused]] ValueFuture<void>&& future,
279 [[maybe_unused]] TimeProvider<Clock>& time_provider,
280 [[maybe_unused]] typename Clock::duration delay) {
281 static_assert(false, "ValueFuture<void> cannot be used with TimeoutOr");
282}
283
296template <typename PrimaryFuture, typename Clock, typename U>
297auto TimeoutOr(PrimaryFuture&& primary_future,
298 TimeProvider<Clock>& time_provider,
299 typename Clock::duration delay,
300 U&& value_or_fn_on_timeout) {
301 using value_type = typename PrimaryFuture::value_type;
302
303 static_assert(
304 std::is_invocable_v<U> || std::is_convertible_v<U, value_type>,
305 "value_or_fn_on_timeout (U) must be callable, or convert to the "
306 "value_type of the primary_future");
307
308 if constexpr (std::is_invocable_v<U>) {
309 return CreateFutureWithTimeout<value_type>(
310 std::forward<PrimaryFuture>(primary_future),
311 time_provider.WaitFor(delay),
313 std::forward<U>(value_or_fn_on_timeout)));
314 } else if constexpr (std::is_convertible_v<U, value_type>) {
315 return CreateFutureWithTimeout<value_type>(
316 std::forward<PrimaryFuture>(primary_future),
317 time_provider.WaitFor(delay),
319 std::forward<U>(value_or_fn_on_timeout)));
320 }
321}
322
330template <
331 typename PrimaryFuture,
332 typename... Args,
333 int&... kExplicitGuard,
334 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
335auto TimeoutOr(PrimaryFuture&& primary_future,
336 typename chrono::SystemClock::duration delay,
337 Args&&... args) {
338 return TimeoutOr<typename std::decay_t<PrimaryFuture>>(
339 std::forward<PrimaryFuture>(primary_future),
341 delay,
342 std::forward<Args>(args)...);
343}
344
355template <typename T, typename Clock>
357 TimeProvider<Clock>& time_provider,
358 typename Clock::duration delay) {
359 return CreateFutureWithTimeout<std::optional<T>>(
360 std::move(future),
361 time_provider.WaitFor(delay),
363 std::nullopt));
364}
365
376template <typename T, typename Clock>
378 TimeProvider<Clock>& time_provider,
379 typename Clock::duration delay) {
380 return CreateFutureWithTimeout<T>(
381 std::move(future),
382 time_provider.WaitFor(delay),
384}
385
396template <typename T, typename Clock>
398 TimeProvider<Clock>& time_provider,
399 typename Clock::duration delay) {
400 using ResultType = typename ReserveSendFuture<T>::value_type;
401 return CreateFutureWithTimeout<ResultType>(
402 std::move(future),
403 time_provider.WaitFor(delay),
405 std::nullopt_t>(std::nullopt));
406}
407
415template <
416 typename PrimaryFuture,
417 int&... kExplicitGuard,
418 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
419auto TimeoutOrClosed(PrimaryFuture&& primary_future,
420 typename chrono::SystemClock::duration delay) {
421 return TimeoutOrClosed(std::forward<PrimaryFuture>(primary_future),
423 delay);
424}
425
428template <typename T, typename Clock = chrono::SystemClock>
430 decltype(Timeout(std::declval<ValueFuture<T>&&>(),
431 std::declval<TimeProvider<Clock>&>(),
432 std::declval<typename Clock::duration>()));
433
440template <typename T, typename U, typename Clock = chrono::SystemClock>
442 decltype(TimeoutOr(std::declval<ValueFuture<T>&&>(),
443 std::declval<TimeProvider<Clock>&>(),
444 std::declval<typename Clock::duration>(),
445 std::declval<U&&>()));
446
450template <typename T, typename Clock = chrono::SystemClock>
452 decltype(Timeout(std::declval<OptionalValueFuture<T>&&>(),
453 std::declval<TimeProvider<Clock>&>(),
454 std::declval<typename Clock::duration>()));
455
462template <typename T, typename U, typename Clock = chrono::SystemClock>
464 decltype(TimeoutOr(std::declval<OptionalValueFuture<T>&&>(),
465 std::declval<TimeProvider<Clock>&>(),
466 std::declval<typename Clock::duration>(),
467 std::declval<U&&>()));
468
471template <typename T, typename Clock = chrono::SystemClock>
473 decltype(Timeout(std::declval<SendFuture<T>&&>(),
474 std::declval<TimeProvider<Clock>&>(),
475 std::declval<typename Clock::duration>()));
476
480template <typename T, typename Clock = chrono::SystemClock>
482 decltype(Timeout(std::declval<ReceiveFuture<T>&&>(),
483 std::declval<TimeProvider<Clock>&>(),
484 std::declval<typename Clock::duration>()));
485
489template <typename T, typename Clock = chrono::SystemClock>
491 decltype(Timeout(std::declval<ReserveSendFuture<T>&&>(),
492 std::declval<TimeProvider<Clock>&>(),
493 std::declval<typename Clock::duration>()));
494
498template <typename T, typename Clock = chrono::SystemClock>
500 decltype(TimeoutOrClosed(std::declval<SendFuture<T>&&>(),
501 std::declval<TimeProvider<Clock>&>(),
502 std::declval<typename Clock::duration>()));
503
507template <typename T, typename Clock = chrono::SystemClock>
509 decltype(TimeoutOrClosed(std::declval<ReceiveFuture<T>&&>(),
510 std::declval<TimeProvider<Clock>&>(),
511 std::declval<typename Clock::duration>()));
512
516template <typename T, typename Clock = chrono::SystemClock>
518 decltype(TimeoutOrClosed(std::declval<ReserveSendFuture<T>&&>(),
519 std::declval<TimeProvider<Clock>&>(),
520 std::declval<typename Clock::duration>()));
521
525template <typename FutureType, typename Clock = chrono::SystemClock>
527 decltype(Timeout(std::declval<FutureType&&>(),
528 std::declval<TimeProvider<Clock>&>(),
529 std::declval<typename Clock::duration>()));
530
537template <typename FutureType, typename U, typename Clock = chrono::SystemClock>
539 decltype(TimeoutOr(std::declval<FutureType&&>(),
540 std::declval<TimeProvider<Clock>&>(),
541 std::declval<typename Clock::duration>(),
542 std::declval<U&&>()));
543
545
546} // namespace pw::async2
Definition: result.h:143
Definition: status.h:120
Definition: context.h:46
Definition: future.h:111
Definition: future_timeout.h:137
Definition: poll.h:138
Definition: channel.h:768
Definition: channel.h:1090
Definition: channel.h:971
Definition: channel.h:1037
Definition: time_provider.h:63
TimeFuture< Clock > WaitFor(typename Clock::duration delay)
Definition: time_provider.h:75
Definition: value_future.h:47
Definition: future.h:47
constexpr PendingType Pending()
Returns a value indicating that an operation was not yet able to complete.
Definition: poll.h:353
constexpr Poll Ready()
Returns a value indicating completion.
Definition: poll.h:337
auto CreateFutureWithTimeout(PrimaryFuture &&primary_future, TimeoutFuture &&timeout_future, TimeoutResolution &&timeout_resolution) -> FutureWithTimeout< T, std::decay_t< PrimaryFuture >, std::decay_t< TimeoutFuture >, std::decay_t< TimeoutResolution > >
Definition: future_timeout.h:200
decltype(Timeout(std::declval< ReceiveFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ReceiveFutureWithTimeout
Definition: future_timeout.h:484
decltype(Timeout(std::declval< ReserveSendFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ReserveSendFutureWithTimeout
Definition: future_timeout.h:493
decltype(Timeout(std::declval< ValueFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ValueFutureWithTimeout
Definition: future_timeout.h:432
decltype(TimeoutOrClosed(std::declval< ReceiveFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ReceiveFutureWithTimeoutOrClosed
Definition: future_timeout.h:511
TimeProvider< chrono::SystemClock > & GetSystemTimeProvider()
Returns a TimeProvider using the "real" SystemClock and SystemTimer.
decltype(TimeoutOr(std::declval< OptionalValueFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >(), std::declval< U && >())) OptionalValueFutureWithTimeoutOr
Definition: future_timeout.h:467
decltype(Timeout(std::declval< SendFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) SendFutureWithTimeout
Definition: future_timeout.h:475
auto Timeout(PrimaryFuture &&primary_future, TimeProvider &time_provider, Duration delay)
Definition: future_timeout.h:232
auto TimeoutOrClosed(ReceiveFuture< T > &&future, TimeProvider< Clock > &time_provider, typename Clock::duration delay)
Definition: future_timeout.h:356
decltype(Timeout(std::declval< OptionalValueFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) OptionalValueFutureWithTimeout
Definition: future_timeout.h:454
decltype(TimeoutOrClosed(std::declval< SendFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) SendFutureWithTimeoutOrClosed
Definition: future_timeout.h:502
decltype(Timeout(std::declval< FutureType && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) CustomFutureWithTimeout
Definition: future_timeout.h:529
decltype(TimeoutOr(std::declval< FutureType && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >(), std::declval< U && >())) CustomFutureWithTimeoutOr
Definition: future_timeout.h:542
decltype(TimeoutOrClosed(std::declval< ReserveSendFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ReserveSendFutureWithTimeoutOrClosed
Definition: future_timeout.h:520
void TimeoutOr(ValueFuture< void > &&future, TimeProvider< Clock > &time_provider, typename Clock::duration delay)
Definition: future_timeout.h:278
decltype(TimeoutOr(std::declval< ValueFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >(), std::declval< U && >())) ValueFutureWithTimeoutOr
Definition: future_timeout.h:445
std::chrono::duration< rep, period > duration
Alias for durations representable with this clock.
Definition: system_clock.h:90
fit::function_impl< function_internal::config::kInlineCallableSize, !function_internal::config::kEnableDynamicAllocation, FunctionType, PW_FUNCTION_DEFAULT_ALLOCATOR_TYPE > Function
Definition: function.h:73
#define PW_NO_UNIQUE_ADDRESS
Definition: compiler.h:297
Definition: future_timeout.h:41
Definition: future_timeout.h:81
Definition: future_timeout.h:53
constexpr ReadyFunctionResultResolution()=default
Cannot be invoked when default constructed; will crash.