TLA Line data Source code
1 : //
2 : // Copyright (c) 2026 Michael Vandeberg
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/cppalliance/capy
8 : //
9 :
10 : #ifndef BOOST_CAPY_TIMEOUT_HPP
11 : #define BOOST_CAPY_TIMEOUT_HPP
12 :
13 : #include <boost/capy/detail/config.hpp>
14 : #include <boost/capy/concept/io_awaitable.hpp>
15 : #include <boost/capy/delay.hpp>
16 : #include <boost/capy/error.hpp>
17 : #include <boost/capy/io_result.hpp>
18 : #include <boost/capy/task.hpp>
19 : #include <boost/capy/when_any.hpp>
20 :
21 : #include <chrono>
22 : #include <system_error>
23 : #include <type_traits>
24 :
25 : namespace boost {
26 : namespace capy {
27 :
28 : namespace detail {
29 :
30 : template<typename T>
31 : struct is_io_result : std::false_type {};
32 :
33 : template<typename... Args>
34 : struct is_io_result<io_result<Args...>> : std::true_type {};
35 :
36 : template<typename T>
37 : inline constexpr bool is_io_result_v = is_io_result<T>::value;
38 :
39 : } // detail
40 :
41 : /** Race an awaitable against a deadline.
42 :
43 : Starts the awaitable and a timer concurrently. If the
44 : awaitable completes first, its result is returned. If the
45 : timer fires first, stop is requested for the awaitable and
46 : a timeout error is produced.
47 :
48 : @par Return Type
49 :
50 : The return type matches the inner awaitable's result type:
51 :
52 : @li For `io_result<...>` types: returns `io_result` with
53 : `ec == error::timeout` and default-initialized values
54 : @li For non-void types: throws `std::system_error(error::timeout)`
55 : @li For void: throws `std::system_error(error::timeout)`
56 :
57 : @par Precision
58 :
59 : The timeout fires at or after the specified duration.
60 :
61 : @par Cancellation
62 :
63 : If the parent's stop token is activated, the inner awaitable
64 : is cancelled normally (not a timeout). The result reflects
65 : the inner awaitable's cancellation behavior.
66 :
67 : @par Example
68 : @code
69 : auto [ec, n] = co_await timeout(sock.read_some(buf), 50ms);
70 : if (ec == cond::timeout) {
71 : // handle timeout
72 : }
73 : @endcode
74 :
75 : @tparam A An IoAwaitable whose result type determines
76 : how timeouts are reported.
77 :
78 : @param a The awaitable to race against the deadline.
79 : @param dur The maximum duration to wait.
80 :
81 : @return `task<awaitable_result_t<A>>`.
82 :
83 : @throws std::system_error with `error::timeout` if the timer
84 : fires first and the result type is not `io_result`.
85 : Exceptions thrown by the inner awaitable propagate
86 : unchanged.
87 :
88 : @see delay, when_any, cond::timeout
89 : */
90 : template<IoAwaitable A, typename Rep, typename Period>
91 HIT 8 : auto timeout(A a, std::chrono::duration<Rep, Period> dur)
92 : -> task<awaitable_result_t<A>>
93 : {
94 : using T = awaitable_result_t<A>;
95 :
96 : auto result = co_await when_any(
97 : std::move(a), delay(dur));
98 :
99 : if(result.index() == 0)
100 : {
101 : // Task completed first
102 : if constexpr (std::is_void_v<T>)
103 : co_return;
104 : else
105 : co_return std::get<0>(std::move(result));
106 : }
107 : else
108 : {
109 : // Timer won
110 : if constexpr (detail::is_io_result_v<T>)
111 : {
112 : T timeout_result{};
113 : timeout_result.ec = make_error_code(error::timeout);
114 : co_return timeout_result;
115 : }
116 : else if constexpr (std::is_void_v<T>)
117 : {
118 : throw std::system_error(
119 : make_error_code(error::timeout));
120 : }
121 : else
122 : {
123 : throw std::system_error(
124 : make_error_code(error::timeout));
125 : }
126 : }
127 16 : }
128 :
129 : } // capy
130 : } // boost
131 :
132 : #endif
|