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
40 using value_type = ReadyType;
41 constexpr Poll<> operator()() const { return Ready(); }
42};
43
50template <typename T>
52 using value_type = T;
53 constexpr explicit ReadyFunctionResultResolution(
54 pw::Function<T()> ready_value_fn)
55 : ready_(std::move(ready_value_fn)) {}
56
57 constexpr Poll<T> operator()() const {
58 return Ready<T>(std::in_place_t{}, ready_());
59 }
60
61 private:
62 pw::Function<T()> ready_;
63};
64
74template <typename T, typename ConstantType, typename CastType = T>
76 using value_type = T;
77 constexpr ReadyConstantValueResolution() = default;
78 constexpr explicit ReadyConstantValueResolution(
79 const cpp20::remove_cvref_t<ConstantType>& value)
80 : constant_(value) {}
81 constexpr explicit ReadyConstantValueResolution(
82 cpp20::remove_cvref_t<ConstantType>&& value)
83 : constant_(std::move(value)) {}
84
85 constexpr Poll<T> operator()() const {
86 return Ready<T>(std::in_place_t{}, CastType(constant_));
87 }
88
89 private:
90 cpp20::remove_cvref_t<ConstantType> constant_;
91};
92
98template <typename T>
100 T,
101 std::integral_constant<pw::Status::Code, PW_STATUS_DEADLINE_EXCEEDED>,
102 pw::Status>;
103
123template <
124 typename T,
125 typename PrimaryFuture,
126 typename TimeoutFuture,
127 typename TimeoutResolution,
128 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>,
129 typename = std::enable_if_t<!std::is_lvalue_reference_v<TimeoutFuture>>,
130 typename = std::enable_if_t<!std::is_lvalue_reference_v<TimeoutResolution>>>
131class [[nodiscard]] FutureWithTimeout
132 : public Future<
133 FutureWithTimeout<T, PrimaryFuture, TimeoutFuture, TimeoutResolution>,
134 T> {
135 static_assert(
136 is_future_v<PrimaryFuture>,
137 "FutureWithTimeout can only be used when PrimaryFuture is a Future type");
138 static_assert(
139 is_future_v<TimeoutFuture>,
140 "FutureWithTimeout can only be used when TimeoutFuture is a Future type");
141
142 public:
143 FutureWithTimeout(PrimaryFuture&& primary_future,
144 TimeoutFuture&& timeout_future,
145 TimeoutResolution&& timeout_resolution)
146 : state_{std::in_place,
147 State{.primary_future = std::move(primary_future),
148 .timeout_future_ = std::move(timeout_future),
149 .timeout_resolution_ = std::move(timeout_resolution)}} {}
150
151 private:
152 using Base = Future<
154 T>;
155 friend Base;
156
158 PW_DASSERT(state_.has_value());
159 auto result = state_->primary_future.Pend(cx);
160 if (result.IsReady()) {
161 return Ready<typename Base::value_type>(std::in_place_t{},
162 std::move(result).value());
163 }
164
165 if (state_->timeout_future_.Pend(cx).IsReady()) {
166 return state_->timeout_resolution_();
167 }
168
169 return Pending();
170 }
171
172 void DoMarkComplete() { state_.reset(); }
173 [[nodiscard]] bool DoIsComplete() const { return !state_.has_value(); }
174
175 struct State {
176 PrimaryFuture primary_future;
177 TimeoutFuture timeout_future_;
178 PW_NO_UNIQUE_ADDRESS TimeoutResolution timeout_resolution_;
179 };
180 std::optional<State> state_;
181};
182
190template <typename T,
191 typename PrimaryFuture,
192 typename TimeoutFuture,
193 typename TimeoutResolution>
194auto CreateFutureWithTimeout(PrimaryFuture&& primary_future,
195 TimeoutFuture&& timeout_future,
196 TimeoutResolution&& timeout_resolution)
198 std::decay_t<PrimaryFuture>,
199 std::decay_t<TimeoutFuture>,
200 std::decay_t<TimeoutResolution>> {
201 return FutureWithTimeout<T,
202 std::decay_t<PrimaryFuture>,
203 std::decay_t<TimeoutFuture>,
204 std::decay_t<TimeoutResolution>>(
205 std::forward<PrimaryFuture>(primary_future),
206 std::forward<TimeoutFuture>(timeout_future),
207 std::forward<TimeoutResolution>(timeout_resolution));
208}
209
220template <
221 typename PrimaryFuture,
222 typename TimeProvider,
223 typename Duration,
224 int&... kExplicitGuard,
225 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
226auto Timeout(PrimaryFuture&& primary_future,
227 TimeProvider& time_provider,
228 Duration delay) {
230 return CreateFutureWithTimeout<ResultType>(
231 std::forward<PrimaryFuture>(primary_future),
232 time_provider.WaitFor(delay),
233 DeadlineExceededResolution<ResultType>());
234}
235
247template <
248 typename PrimaryFuture,
249 int&... kExplicitGuard,
250 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
251auto Timeout(PrimaryFuture&& primary_future,
252 typename chrono::SystemClock::duration delay) {
253 using ResultType = Result<typename std::decay_t<PrimaryFuture>::value_type>;
254 return CreateFutureWithTimeout<ResultType>(
255 std::forward<PrimaryFuture>(primary_future),
256 GetSystemTimeProvider().WaitFor(delay),
257 DeadlineExceededResolution<ResultType>());
258}
259
271template <typename Clock>
272void TimeoutOr([[maybe_unused]] ValueFuture<void>&& future,
273 [[maybe_unused]] TimeProvider<Clock>& time_provider,
274 [[maybe_unused]] typename Clock::duration delay) {
275 static_assert(false, "ValueFuture<void> cannot be used with TimeoutOr");
276}
277
290template <typename PrimaryFuture, typename Clock, typename U>
291auto TimeoutOr(PrimaryFuture&& primary_future,
292 TimeProvider<Clock>& time_provider,
293 typename Clock::duration delay,
294 U&& value_or_fn_on_timeout) {
295 using value_type = typename PrimaryFuture::value_type;
296
297 static_assert(
298 std::is_invocable_v<U> || std::is_convertible_v<U, value_type>,
299 "value_or_fn_on_timeout (U) must be callable, or convert to the "
300 "value_type of the primary_future");
301
302 if constexpr (std::is_invocable_v<U>) {
303 return CreateFutureWithTimeout<value_type>(
304 std::forward<PrimaryFuture>(primary_future),
305 time_provider.WaitFor(delay),
306 ReadyFunctionResultResolution<value_type>(
307 std::forward<U>(value_or_fn_on_timeout)));
308 } else if constexpr (std::is_convertible_v<U, value_type>) {
309 return CreateFutureWithTimeout<value_type>(
310 std::forward<PrimaryFuture>(primary_future),
311 time_provider.WaitFor(delay),
312 ReadyConstantValueResolution<value_type, U>(
313 std::forward<U>(value_or_fn_on_timeout)));
314 }
315}
316
324template <
325 typename PrimaryFuture,
326 typename... Args,
327 int&... kExplicitGuard,
328 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
329auto TimeoutOr(PrimaryFuture&& primary_future,
330 typename chrono::SystemClock::duration delay,
331 Args&&... args) {
332 return TimeoutOr<typename std::decay_t<PrimaryFuture>>(
333 std::forward<PrimaryFuture>(primary_future),
335 delay,
336 std::forward<Args>(args)...);
337}
338
349template <typename T, typename Clock>
350auto TimeoutOrClosed(ReceiveFuture<T>&& future,
351 TimeProvider<Clock>& time_provider,
352 typename Clock::duration delay) {
353 return CreateFutureWithTimeout<std::optional<T>>(
354 std::move(future),
355 time_provider.WaitFor(delay),
356 ReadyConstantValueResolution<std::optional<T>, std::nullopt_t>(
357 std::nullopt));
358}
359
370template <typename T, typename Clock>
371auto TimeoutOrClosed(SendFuture<T>&& future,
372 TimeProvider<Clock>& time_provider,
373 typename Clock::duration delay) {
374 return CreateFutureWithTimeout<T>(
375 std::move(future),
376 time_provider.WaitFor(delay),
377 ReadyConstantValueResolution<bool, std::false_type>());
378}
379
390template <typename T, typename Clock>
391auto TimeoutOrClosed(ReserveSendFuture<T>&& future,
392 TimeProvider<Clock>& time_provider,
393 typename Clock::duration delay) {
394 using ResultType = typename ReserveSendFuture<T>::value_type;
395 return CreateFutureWithTimeout<ResultType>(
396 std::move(future),
397 time_provider.WaitFor(delay),
398 ReadyConstantValueResolution<std::optional<SendReservation<T>>,
399 std::nullopt_t>(std::nullopt));
400}
401
409template <
410 typename PrimaryFuture,
411 int&... kExplicitGuard,
412 typename = std::enable_if_t<!std::is_lvalue_reference_v<PrimaryFuture>>>
413auto TimeoutOrClosed(PrimaryFuture&& primary_future,
414 typename chrono::SystemClock::duration delay) {
415 return TimeoutOrClosed(std::forward<PrimaryFuture>(primary_future),
417 delay);
418}
419
422template <typename T, typename Clock = chrono::SystemClock>
423using ValueFutureWithTimeout =
424 decltype(Timeout(std::declval<ValueFuture<T>&&>(),
425 std::declval<TimeProvider<Clock>&>(),
426 std::declval<typename Clock::duration>()));
427
434template <typename T, typename U, typename Clock = chrono::SystemClock>
435using ValueFutureWithTimeoutOr =
436 decltype(TimeoutOr(std::declval<ValueFuture<T>&&>(),
437 std::declval<TimeProvider<Clock>&>(),
438 std::declval<typename Clock::duration>(),
439 std::declval<U&&>()));
440
443template <typename T, typename Clock = chrono::SystemClock>
444using SendFutureWithTimeout =
445 decltype(Timeout(std::declval<SendFuture<T>&&>(),
446 std::declval<TimeProvider<Clock>&>(),
447 std::declval<typename Clock::duration>()));
448
452template <typename T, typename Clock = chrono::SystemClock>
453using ReceiveFutureWithTimeout =
454 decltype(Timeout(std::declval<ReceiveFuture<T>&&>(),
455 std::declval<TimeProvider<Clock>&>(),
456 std::declval<typename Clock::duration>()));
457
461template <typename T, typename Clock = chrono::SystemClock>
462using ReserveSendFutureWithTimeout =
463 decltype(Timeout(std::declval<ReserveSendFuture<T>&&>(),
464 std::declval<TimeProvider<Clock>&>(),
465 std::declval<typename Clock::duration>()));
466
470template <typename T, typename Clock = chrono::SystemClock>
471using SendFutureWithTimeoutOrClosed =
472 decltype(TimeoutOrClosed(std::declval<SendFuture<T>&&>(),
473 std::declval<TimeProvider<Clock>&>(),
474 std::declval<typename Clock::duration>()));
475
479template <typename T, typename Clock = chrono::SystemClock>
480using ReceiveFutureWithTimeoutOrClosed =
481 decltype(TimeoutOrClosed(std::declval<ReceiveFuture<T>&&>(),
482 std::declval<TimeProvider<Clock>&>(),
483 std::declval<typename Clock::duration>()));
484
488template <typename T, typename Clock = chrono::SystemClock>
489using ReserveSendFutureWithTimeoutOrClosed =
490 decltype(TimeoutOrClosed(std::declval<ReserveSendFuture<T>&&>(),
491 std::declval<TimeProvider<Clock>&>(),
492 std::declval<typename Clock::duration>()));
493
497template <typename FutureType, typename Clock = chrono::SystemClock>
498using CustomFutureWithTimeout =
499 decltype(Timeout(std::declval<FutureType&&>(),
500 std::declval<TimeProvider<Clock>&>(),
501 std::declval<typename Clock::duration>()));
502
509template <typename FutureType, typename U, typename Clock = chrono::SystemClock>
510using CustomFutureWithTimeoutOr =
511 decltype(TimeoutOr(std::declval<FutureType&&>(),
512 std::declval<TimeProvider<Clock>&>(),
513 std::declval<typename Clock::duration>(),
514 std::declval<U&&>()));
515
516} // namespace pw::async2
Definition: result.h:143
Definition: status.h:120
Definition: context.h:54
Definition: future.h:62
Definition: future_timeout.h:134
Definition: poll.h:60
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
TimeProvider< chrono::SystemClock > & GetSystemTimeProvider()
Returns a TimeProvider using the "real" SystemClock and SystemTimer.
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:39
Definition: future_timeout.h:75
Definition: future_timeout.h:51
Definition: poll.h:36