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 = ReadyType;
43 constexpr Poll<> operator()() const { return Ready(); }
44};
45
52template <typename T>
54 using value_type = T;
55 constexpr explicit ReadyFunctionResultResolution(
56 pw::Function<T()> ready_value_fn)
57 : ready_(std::move(ready_value_fn)) {}
58
59 constexpr Poll<T> operator()() const {
60 return Ready<T>(std::in_place_t{}, ready_());
61 }
62
63 private:
64 pw::Function<T()> ready_;
65};
66
76template <typename T, typename ConstantType, typename CastType = T>
78 using value_type = T;
79 constexpr ReadyConstantValueResolution() = default;
80 constexpr explicit ReadyConstantValueResolution(
81 const cpp20::remove_cvref_t<ConstantType>& value)
82 : constant_(value) {}
83 constexpr explicit ReadyConstantValueResolution(
84 cpp20::remove_cvref_t<ConstantType>&& value)
85 : constant_(std::move(value)) {}
86
87 constexpr Poll<T> operator()() const {
88 return Ready<T>(std::in_place_t{}, CastType(constant_));
89 }
90
91 private:
92 cpp20::remove_cvref_t<ConstantType> constant_;
93};
94
100template <typename T>
102 T,
103 std::integral_constant<pw::Status::Code, PW_STATUS_DEADLINE_EXCEEDED>,
104 pw::Status>;
105
125template <
126 typename T,
127 typename PrimaryFuture,
128 typename TimeoutFuture,
129 typename TimeoutResolution,
130 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>,
131 typename = std::enable_if_t<!std::is_lvalue_reference_v<TimeoutFuture>>,
132 typename = std::enable_if_t<!std::is_lvalue_reference_v<TimeoutResolution>>>
133class [[nodiscard]] FutureWithTimeout
134 : public Future<
135 FutureWithTimeout<T, PrimaryFuture, TimeoutFuture, TimeoutResolution>,
136 T> {
137 static_assert(
138 is_future_v<PrimaryFuture>,
139 "FutureWithTimeout can only be used when PrimaryFuture is a Future type");
140 static_assert(
141 is_future_v<TimeoutFuture>,
142 "FutureWithTimeout can only be used when TimeoutFuture is a Future type");
143
144 public:
145 FutureWithTimeout(PrimaryFuture&& primary_future,
146 TimeoutFuture&& timeout_future,
147 TimeoutResolution&& timeout_resolution)
148 : state_{std::in_place,
149 State{.primary_future = std::move(primary_future),
150 .timeout_future_ = std::move(timeout_future),
151 .timeout_resolution_ = std::move(timeout_resolution)}} {}
152
153 private:
154 using Base = Future<
156 T>;
157 friend Base;
158
160 PW_DASSERT(state_.has_value());
161 auto result = state_->primary_future.Pend(cx);
162 if (result.IsReady()) {
163 return Ready<typename Base::value_type>(std::in_place_t{},
164 std::move(result).value());
165 }
166
167 if (state_->timeout_future_.Pend(cx).IsReady()) {
168 return state_->timeout_resolution_();
169 }
170
171 return Pending();
172 }
173
174 void DoMarkComplete() { state_.reset(); }
175 [[nodiscard]] bool DoIsComplete() const { return !state_.has_value(); }
176
177 struct State {
178 PrimaryFuture primary_future;
179 TimeoutFuture timeout_future_;
180 PW_NO_UNIQUE_ADDRESS TimeoutResolution timeout_resolution_;
181 };
182 std::optional<State> state_;
183};
184
192template <typename T,
193 typename PrimaryFuture,
194 typename TimeoutFuture,
195 typename TimeoutResolution>
196auto CreateFutureWithTimeout(PrimaryFuture&& primary_future,
197 TimeoutFuture&& timeout_future,
198 TimeoutResolution&& timeout_resolution)
200 std::decay_t<PrimaryFuture>,
201 std::decay_t<TimeoutFuture>,
202 std::decay_t<TimeoutResolution>> {
203 return FutureWithTimeout<T,
204 std::decay_t<PrimaryFuture>,
205 std::decay_t<TimeoutFuture>,
206 std::decay_t<TimeoutResolution>>(
207 std::forward<PrimaryFuture>(primary_future),
208 std::forward<TimeoutFuture>(timeout_future),
209 std::forward<TimeoutResolution>(timeout_resolution));
210}
211
222template <
223 typename PrimaryFuture,
224 typename TimeProvider,
225 typename Duration,
226 int&... kExplicitGuard,
227 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
228auto Timeout(PrimaryFuture&& primary_future,
229 TimeProvider& time_provider,
230 Duration delay) {
232 return CreateFutureWithTimeout<ResultType>(
233 std::forward<PrimaryFuture>(primary_future),
234 time_provider.WaitFor(delay),
236}
237
249template <
250 typename PrimaryFuture,
251 int&... kExplicitGuard,
252 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
253auto Timeout(PrimaryFuture&& primary_future,
254 typename chrono::SystemClock::duration delay) {
256 return CreateFutureWithTimeout<ResultType>(
257 std::forward<PrimaryFuture>(primary_future),
258 GetSystemTimeProvider().WaitFor(delay),
260}
261
273template <typename Clock>
274void TimeoutOr([[maybe_unused]] ValueFuture<void>&& future,
275 [[maybe_unused]] TimeProvider<Clock>& time_provider,
276 [[maybe_unused]] typename Clock::duration delay) {
277 static_assert(false, "ValueFuture<void> cannot be used with TimeoutOr");
278}
279
292template <typename PrimaryFuture, typename Clock, typename U>
293auto TimeoutOr(PrimaryFuture&& primary_future,
294 TimeProvider<Clock>& time_provider,
295 typename Clock::duration delay,
296 U&& value_or_fn_on_timeout) {
297 using value_type = typename PrimaryFuture::value_type;
298
299 static_assert(
300 std::is_invocable_v<U> || std::is_convertible_v<U, value_type>,
301 "value_or_fn_on_timeout (U) must be callable, or convert to the "
302 "value_type of the primary_future");
303
304 if constexpr (std::is_invocable_v<U>) {
305 return CreateFutureWithTimeout<value_type>(
306 std::forward<PrimaryFuture>(primary_future),
307 time_provider.WaitFor(delay),
309 std::forward<U>(value_or_fn_on_timeout)));
310 } else if constexpr (std::is_convertible_v<U, value_type>) {
311 return CreateFutureWithTimeout<value_type>(
312 std::forward<PrimaryFuture>(primary_future),
313 time_provider.WaitFor(delay),
315 std::forward<U>(value_or_fn_on_timeout)));
316 }
317}
318
326template <
327 typename PrimaryFuture,
328 typename... Args,
329 int&... kExplicitGuard,
330 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
331auto TimeoutOr(PrimaryFuture&& primary_future,
332 typename chrono::SystemClock::duration delay,
333 Args&&... args) {
334 return TimeoutOr<typename std::decay_t<PrimaryFuture>>(
335 std::forward<PrimaryFuture>(primary_future),
337 delay,
338 std::forward<Args>(args)...);
339}
340
351template <typename T, typename Clock>
353 TimeProvider<Clock>& time_provider,
354 typename Clock::duration delay) {
355 return CreateFutureWithTimeout<std::optional<T>>(
356 std::move(future),
357 time_provider.WaitFor(delay),
359 std::nullopt));
360}
361
372template <typename T, typename Clock>
374 TimeProvider<Clock>& time_provider,
375 typename Clock::duration delay) {
376 return CreateFutureWithTimeout<T>(
377 std::move(future),
378 time_provider.WaitFor(delay),
380}
381
392template <typename T, typename Clock>
394 TimeProvider<Clock>& time_provider,
395 typename Clock::duration delay) {
396 using ResultType = typename ReserveSendFuture<T>::value_type;
397 return CreateFutureWithTimeout<ResultType>(
398 std::move(future),
399 time_provider.WaitFor(delay),
401 std::nullopt_t>(std::nullopt));
402}
403
411template <
412 typename PrimaryFuture,
413 int&... kExplicitGuard,
414 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
415auto TimeoutOrClosed(PrimaryFuture&& primary_future,
416 typename chrono::SystemClock::duration delay) {
417 return TimeoutOrClosed(std::forward<PrimaryFuture>(primary_future),
419 delay);
420}
421
424template <typename T, typename Clock = chrono::SystemClock>
426 decltype(Timeout(std::declval<ValueFuture<T>&&>(),
427 std::declval<TimeProvider<Clock>&>(),
428 std::declval<typename Clock::duration>()));
429
436template <typename T, typename U, typename Clock = chrono::SystemClock>
438 decltype(TimeoutOr(std::declval<ValueFuture<T>&&>(),
439 std::declval<TimeProvider<Clock>&>(),
440 std::declval<typename Clock::duration>(),
441 std::declval<U&&>()));
442
445template <typename T, typename Clock = chrono::SystemClock>
447 decltype(Timeout(std::declval<SendFuture<T>&&>(),
448 std::declval<TimeProvider<Clock>&>(),
449 std::declval<typename Clock::duration>()));
450
454template <typename T, typename Clock = chrono::SystemClock>
456 decltype(Timeout(std::declval<ReceiveFuture<T>&&>(),
457 std::declval<TimeProvider<Clock>&>(),
458 std::declval<typename Clock::duration>()));
459
463template <typename T, typename Clock = chrono::SystemClock>
465 decltype(Timeout(std::declval<ReserveSendFuture<T>&&>(),
466 std::declval<TimeProvider<Clock>&>(),
467 std::declval<typename Clock::duration>()));
468
472template <typename T, typename Clock = chrono::SystemClock>
474 decltype(TimeoutOrClosed(std::declval<SendFuture<T>&&>(),
475 std::declval<TimeProvider<Clock>&>(),
476 std::declval<typename Clock::duration>()));
477
481template <typename T, typename Clock = chrono::SystemClock>
483 decltype(TimeoutOrClosed(std::declval<ReceiveFuture<T>&&>(),
484 std::declval<TimeProvider<Clock>&>(),
485 std::declval<typename Clock::duration>()));
486
490template <typename T, typename Clock = chrono::SystemClock>
492 decltype(TimeoutOrClosed(std::declval<ReserveSendFuture<T>&&>(),
493 std::declval<TimeProvider<Clock>&>(),
494 std::declval<typename Clock::duration>()));
495
499template <typename FutureType, typename Clock = chrono::SystemClock>
501 decltype(Timeout(std::declval<FutureType&&>(),
502 std::declval<TimeProvider<Clock>&>(),
503 std::declval<typename Clock::duration>()));
504
511template <typename FutureType, typename U, typename Clock = chrono::SystemClock>
513 decltype(TimeoutOr(std::declval<FutureType&&>(),
514 std::declval<TimeProvider<Clock>&>(),
515 std::declval<typename Clock::duration>(),
516 std::declval<U&&>()));
517
519
520} // namespace pw::async2
Definition: result.h:143
Definition: status.h:120
Definition: context.h:54
Definition: future.h:65
Definition: future_timeout.h:136
Definition: poll.h:60
Definition: channel.h:770
Definition: channel.h:1088
Definition: channel.h:972
Definition: channel.h:1035
Definition: time_provider.h:63
TimeFuture< Clock > WaitFor(typename Clock::duration delay)
Definition: time_provider.h:75
Definition: value_future.h:46
constexpr PendingType Pending()
Returns a value indicating that an operation was not yet able to complete.
Definition: poll.h:271
constexpr Poll Ready()
Returns a value indicating completion.
Definition: poll.h:255
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:196
decltype(Timeout(std::declval< ReceiveFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ReceiveFutureWithTimeout
Definition: future_timeout.h:458
decltype(Timeout(std::declval< ReserveSendFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ReserveSendFutureWithTimeout
Definition: future_timeout.h:467
decltype(Timeout(std::declval< ValueFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ValueFutureWithTimeout
Definition: future_timeout.h:428
decltype(TimeoutOrClosed(std::declval< ReceiveFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ReceiveFutureWithTimeoutOrClosed
Definition: future_timeout.h:485
TimeProvider< chrono::SystemClock > & GetSystemTimeProvider()
Returns a TimeProvider using the "real" SystemClock and SystemTimer.
decltype(Timeout(std::declval< SendFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) SendFutureWithTimeout
Definition: future_timeout.h:449
auto Timeout(PrimaryFuture &&primary_future, TimeProvider &time_provider, Duration delay)
Definition: future_timeout.h:228
auto TimeoutOrClosed(ReceiveFuture< T > &&future, TimeProvider< Clock > &time_provider, typename Clock::duration delay)
Definition: future_timeout.h:352
decltype(TimeoutOrClosed(std::declval< SendFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) SendFutureWithTimeoutOrClosed
Definition: future_timeout.h:476
decltype(Timeout(std::declval< FutureType && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) CustomFutureWithTimeout
Definition: future_timeout.h:503
decltype(TimeoutOr(std::declval< FutureType && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >(), std::declval< U && >())) CustomFutureWithTimeoutOr
Definition: future_timeout.h:516
decltype(TimeoutOrClosed(std::declval< ReserveSendFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >())) ReserveSendFutureWithTimeoutOrClosed
Definition: future_timeout.h:494
void TimeoutOr(ValueFuture< void > &&future, TimeProvider< Clock > &time_provider, typename Clock::duration delay)
Definition: future_timeout.h:274
decltype(TimeoutOr(std::declval< ValueFuture< T > && >(), std::declval< TimeProvider< Clock > & >(), std::declval< typename Clock::duration >(), std::declval< U && >())) ValueFutureWithTimeoutOr
Definition: future_timeout.h:441
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:77
Definition: future_timeout.h:53
Definition: poll.h:36