include/boost/capy/timeout.hpp
100.0% Lines (2/2)
100.0% Functions (6/6)
| Line | TLA | Hits | 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 | 8x | 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 | 16x | } | |
| 128 | |||
| 129 | } // capy | ||
| 130 | } // boost | ||
| 131 | |||
| 132 | #endif | ||
| 133 |