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 static_assert(
97 std::is_default_constructible_v<cpp20::remove_cvref_t<ConstantType>>,
98 "ConstantType must be default constructible");
99 cpp20::remove_cvref_t<ConstantType> constant_;
100};
101
102template <typename T, typename CastType>
103struct ReadyConstantValueResolution<T, std::nullopt_t, CastType> {
104 using value_type = T;
105 constexpr ReadyConstantValueResolution() = default;
106 constexpr explicit ReadyConstantValueResolution(std::nullopt_t) {}
107
108 constexpr Poll<T> operator()() const {
109 return Ready<T>(std::in_place_t{}, CastType(std::nullopt));
110 }
111};
112
118template <typename T>
120 T,
121 std::integral_constant<pw::Status::Code, PW_STATUS_DEADLINE_EXCEEDED>,
122 pw::Status>;
123
143template <
144 typename T,
145 typename PrimaryFuture,
146 typename TimeoutFuture,
147 typename TimeoutResolution,
148 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>,
149 typename = std::enable_if_t<!std::is_lvalue_reference_v<TimeoutFuture>>,
150 typename = std::enable_if_t<!std::is_lvalue_reference_v<TimeoutResolution>>>
151class [[nodiscard]] FutureWithTimeout {
152 static_assert(
154 "FutureWithTimeout can only be used when PrimaryFuture is a Future type");
155 static_assert(
157 "FutureWithTimeout can only be used when TimeoutFuture is a Future type");
158
159 public:
160 using value_type = T;
161
162 constexpr FutureWithTimeout() = default;
163
164 FutureWithTimeout(PrimaryFuture&& primary_future,
165 TimeoutFuture&& timeout_future,
166 TimeoutResolution&& timeout_resolution)
167 : primary_future_(std::move(primary_future)),
168 timeout_future_(std::move(timeout_future)),
169 timeout_resolution_(std::move(timeout_resolution)),
170 state_(FutureState::kPending) {}
171
172 [[nodiscard]] constexpr bool is_pendable() const {
173 return state_.is_pendable();
174 }
175
176 [[nodiscard]] constexpr bool is_complete() const {
177 return state_.is_complete();
178 }
179
180 Poll<value_type> Pend(Context& cx) {
181 PW_ASSERT(is_pendable());
182 auto result = primary_future_.Pend(cx);
183 if (result.IsReady()) {
184 state_.MarkComplete();
185 return Ready<value_type>(std::in_place, std::move(result).value());
186 }
187
188 if (timeout_future_.Pend(cx).IsReady()) {
189 state_.MarkComplete();
190 return timeout_resolution_();
191 }
192
193 return Pending();
194 }
195
196 private:
197 PrimaryFuture primary_future_;
198 TimeoutFuture timeout_future_;
199 PW_NO_UNIQUE_ADDRESS TimeoutResolution timeout_resolution_;
200 FutureState state_;
201};
202
210template <typename T,
211 typename PrimaryFuture,
212 typename TimeoutFuture,
213 typename TimeoutResolution>
214auto CreateFutureWithTimeout(PrimaryFuture&& primary_future,
215 TimeoutFuture&& timeout_future,
216 TimeoutResolution&& timeout_resolution)
218 std::decay_t<PrimaryFuture>,
219 std::decay_t<TimeoutFuture>,
220 std::decay_t<TimeoutResolution>> {
221 return FutureWithTimeout<T,
222 std::decay_t<PrimaryFuture>,
223 std::decay_t<TimeoutFuture>,
224 std::decay_t<TimeoutResolution>>(
225 std::forward<PrimaryFuture>(primary_future),
226 std::forward<TimeoutFuture>(timeout_future),
227 std::forward<TimeoutResolution>(timeout_resolution));
228}
229
240template <
241 typename PrimaryFuture,
242 typename TimeProvider,
243 typename Duration,
244 int&... kExplicitGuard,
245 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
246auto Timeout(PrimaryFuture&& primary_future,
247 TimeProvider& time_provider,
248 Duration delay) {
250 return CreateFutureWithTimeout<ResultType>(
251 std::forward<PrimaryFuture>(primary_future),
252 time_provider.WaitFor(delay),
254}
255
267template <
268 typename PrimaryFuture,
269 int&... kExplicitGuard,
270 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
271auto Timeout(PrimaryFuture&& primary_future,
272 typename chrono::SystemClock::duration delay) {
274 return CreateFutureWithTimeout<ResultType>(
275 std::forward<PrimaryFuture>(primary_future),
276 GetSystemTimeProvider().WaitFor(delay),
278}
279
291template <typename Clock>
292void TimeoutOr([[maybe_unused]] ValueFuture<void>&& future,
293 [[maybe_unused]] TimeProvider<Clock>& time_provider,
294 [[maybe_unused]] typename Clock::duration delay) {
295 static_assert(false, "ValueFuture<void> cannot be used with TimeoutOr");
296}
297
310template <typename PrimaryFuture, typename Clock, typename U>
311auto TimeoutOr(PrimaryFuture&& primary_future,
312 TimeProvider<Clock>& time_provider,
313 typename Clock::duration delay,
314 U&& value_or_fn_on_timeout) {
315 using value_type = typename PrimaryFuture::value_type;
316
317 static_assert(
318 std::is_invocable_v<U> || std::is_convertible_v<U, value_type>,
319 "value_or_fn_on_timeout (U) must be callable, or convert to the "
320 "value_type of the primary_future");
321
322 if constexpr (std::is_invocable_v<U>) {
323 return CreateFutureWithTimeout<value_type>(
324 std::forward<PrimaryFuture>(primary_future),
325 time_provider.WaitFor(delay),
327 std::forward<U>(value_or_fn_on_timeout)));
328 } else if constexpr (std::is_convertible_v<U, value_type>) {
329 return CreateFutureWithTimeout<value_type>(
330 std::forward<PrimaryFuture>(primary_future),
331 time_provider.WaitFor(delay),
333 std::forward<U>(value_or_fn_on_timeout)));
334 }
335}
336
344template <
345 typename PrimaryFuture,
346 typename... Args,
347 int&... kExplicitGuard,
348 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
349auto TimeoutOr(PrimaryFuture&& primary_future,
350 typename chrono::SystemClock::duration delay,
351 Args&&... args) {
352 return TimeoutOr<typename std::decay_t<PrimaryFuture>>(
353 std::forward<PrimaryFuture>(primary_future),
355 delay,
356 std::forward<Args>(args)...);
357}
358
369template <typename T, typename Clock>
371 TimeProvider<Clock>& time_provider,
372 typename Clock::duration delay) {
373 return CreateFutureWithTimeout<std::optional<T>>(
374 std::move(future),
375 time_provider.WaitFor(delay),
377 std::nullopt));
378}
379
390template <typename T, typename Clock>
392 TimeProvider<Clock>& time_provider,
393 typename Clock::duration delay) {
394 return CreateFutureWithTimeout<T>(
395 std::move(future),
396 time_provider.WaitFor(delay),
398}
399
410template <typename T, typename Clock>
412 TimeProvider<Clock>& time_provider,
413 typename Clock::duration delay) {
414 using ResultType = typename ReserveSendFuture<T>::value_type;
415 return CreateFutureWithTimeout<ResultType>(
416 std::move(future),
417 time_provider.WaitFor(delay),
419 std::nullopt_t>(std::nullopt));
420}
421
429template <
430 typename PrimaryFuture,
431 int&... kExplicitGuard,
432 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
433auto TimeoutOrClosed(PrimaryFuture&& primary_future,
434 typename chrono::SystemClock::duration delay) {
435 return TimeoutOrClosed(std::forward<PrimaryFuture>(primary_future),
437 delay);
438}
439
442template <typename T, typename Clock = chrono::SystemClock>
444 decltype(Timeout(std::declval<ValueFuture<T>&&>(),
445 std::declval<TimeProvider<Clock>&>(),
446 std::declval<typename Clock::duration>()));
447
454template <typename T, typename U, typename Clock = chrono::SystemClock>
456 decltype(TimeoutOr(std::declval<ValueFuture<T>&&>(),
457 std::declval<TimeProvider<Clock>&>(),
458 std::declval<typename Clock::duration>(),
459 std::declval<U&&>()));
460
464template <typename T, typename Clock = chrono::SystemClock>
466 decltype(Timeout(std::declval<OptionalValueFuture<T>&&>(),
467 std::declval<TimeProvider<Clock>&>(),
468 std::declval<typename Clock::duration>()));
469
476template <typename T, typename U, typename Clock = chrono::SystemClock>
478 decltype(TimeoutOr(std::declval<OptionalValueFuture<T>&&>(),
479 std::declval<TimeProvider<Clock>&>(),
480 std::declval<typename Clock::duration>(),
481 std::declval<U&&>()));
482
485template <typename T, typename Clock = chrono::SystemClock>
487 decltype(Timeout(std::declval<SendFuture<T>&&>(),
488 std::declval<TimeProvider<Clock>&>(),
489 std::declval<typename Clock::duration>()));
490
494template <typename T, typename Clock = chrono::SystemClock>
496 decltype(Timeout(std::declval<ReceiveFuture<T>&&>(),
497 std::declval<TimeProvider<Clock>&>(),
498 std::declval<typename Clock::duration>()));
499
503template <typename T, typename Clock = chrono::SystemClock>
505 decltype(Timeout(std::declval<ReserveSendFuture<T>&&>(),
506 std::declval<TimeProvider<Clock>&>(),
507 std::declval<typename Clock::duration>()));
508
512template <typename T, typename Clock = chrono::SystemClock>
514 decltype(TimeoutOrClosed(std::declval<SendFuture<T>&&>(),
515 std::declval<TimeProvider<Clock>&>(),
516 std::declval<typename Clock::duration>()));
517
521template <typename T, typename Clock = chrono::SystemClock>
523 decltype(TimeoutOrClosed(std::declval<ReceiveFuture<T>&&>(),
524 std::declval<TimeProvider<Clock>&>(),
525 std::declval<typename Clock::duration>()));
526
530template <typename T, typename Clock = chrono::SystemClock>
532 decltype(TimeoutOrClosed(std::declval<ReserveSendFuture<T>&&>(),
533 std::declval<TimeProvider<Clock>&>(),
534 std::declval<typename Clock::duration>()));
535
539template <typename FutureType, typename Clock = chrono::SystemClock>
541 decltype(Timeout(std::declval<FutureType&&>(),
542 std::declval<TimeProvider<Clock>&>(),
543 std::declval<typename Clock::duration>()));
544
551template <typename FutureType, typename U, typename Clock = chrono::SystemClock>
553 decltype(TimeoutOr(std::declval<FutureType&&>(),
554 std::declval<TimeProvider<Clock>&>(),
555 std::declval<typename Clock::duration>(),
556 std::declval<U&&>()));
557
559
560} // namespace pw::async2
Definition: result.h:143
Definition: status.h:120
Definition: context.h:46
Definition: future.h:111
Definition: future_timeout.h:151
Definition: poll.h:138
Definition: channel.h:771
Definition: channel.h:1095
Definition: channel.h:975
Definition: channel.h:1042
Definition: time_provider.h:63
TimeFuture< Clock > WaitFor(typename Clock::duration delay)
Definition: time_provider.h:75
Definition: value_future.h:51
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:214
decltype(Timeout(std::declval< ReceiveFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ReceiveFutureWithTimeout
Definition: future_timeout.h:498
decltype(Timeout(std::declval< ReserveSendFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ReserveSendFutureWithTimeout
Definition: future_timeout.h:507
decltype(Timeout(std::declval< ValueFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ValueFutureWithTimeout
Definition: future_timeout.h:446
decltype(TimeoutOrClosed(std::declval< ReceiveFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ReceiveFutureWithTimeoutOrClosed
Definition: future_timeout.h:525
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:481
decltype(Timeout(std::declval< SendFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) SendFutureWithTimeout
Definition: future_timeout.h:489
auto Timeout(PrimaryFuture &&primary_future, TimeProvider &time_provider, Duration delay)
Definition: future_timeout.h:246
auto TimeoutOrClosed(ReceiveFuture< T > &&future, TimeProvider< Clock > &time_provider, typename Clock::duration delay)
Definition: future_timeout.h:370
decltype(Timeout(std::declval< OptionalValueFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) OptionalValueFutureWithTimeout
Definition: future_timeout.h:468
decltype(TimeoutOrClosed(std::declval< SendFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) SendFutureWithTimeoutOrClosed
Definition: future_timeout.h:516
decltype(Timeout(std::declval< FutureType && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) CustomFutureWithTimeout
Definition: future_timeout.h:543
decltype(TimeoutOr(std::declval< FutureType && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >(), std::declval< U && >())) CustomFutureWithTimeoutOr
Definition: future_timeout.h:556
decltype(TimeoutOrClosed(std::declval< ReserveSendFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ReserveSendFutureWithTimeoutOrClosed
Definition: future_timeout.h:534
void TimeoutOr(ValueFuture< void > &&future, TimeProvider< Clock > &time_provider, typename Clock::duration delay)
Definition: future_timeout.h:292
decltype(TimeoutOr(std::declval< ValueFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >(), std::declval< U && >())) ValueFutureWithTimeoutOr
Definition: future_timeout.h:459
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.