userver: userver/drivers/subscribable_futures.hpp Source File
Loading...
Searching...
No Matches
subscribable_futures.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/drivers/subscribable_futures.hpp
4/// @brief @copybrief drivers::WaitForSubscribableFuture
5
6#include <boost/intrusive_ptr.hpp>
7#include <boost/smart_ptr/intrusive_ref_counter.hpp>
8
9#include <userver/engine/deadline.hpp>
10#include <userver/engine/exception.hpp>
11#include <userver/engine/future_status.hpp>
12#include <userver/engine/single_consumer_event.hpp>
13#include <userver/engine/task/cancel.hpp>
14#include <userver/utils/make_intrusive_ptr.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace drivers {
19
20/// @ingroup userver_concurrency
21///
22/// @brief An adaptor for working with certain external futures.
23///
24/// The `SubscribableFuture` must have a `Subscribe(Callback)` method that calls
25/// the callback when the future is ready. If the future is already ready, then
26/// `Subscribe` must call the callback immediately. If the promise is dropped
27/// and will never be fulfilled properly, then the `SubscribableFuture` should
28/// call the callback anyway.
29///
30/// @throws engine::WaitInterruptedException on task cancellation
31template <typename SubscribableFuture>
32void WaitForSubscribableFuture(SubscribableFuture&& future);
33
34/// @overload
35/// @ingroup userver_concurrency
36///
37/// @brief Same as drivers::WaitForSubscribableFuture, but returns an error code
38/// instead of throwing.
39template <typename SubscribableFuture>
40[[nodiscard]] engine::FutureStatus TryWaitForSubscribableFuture(
41 SubscribableFuture&& future, engine::Deadline deadline);
42
43namespace impl {
44
45struct EventHolder final : boost::intrusive_ref_counter<EventHolder> {
46 engine::SingleConsumerEvent event{engine::SingleConsumerEvent::NoAutoReset{}};
47};
48
49} // namespace impl
50
51template <typename SubscribableFuture>
52void WaitForSubscribableFuture(SubscribableFuture&& future) {
53 if (drivers::TryWaitForSubscribableFuture(future, engine::Deadline{}) !=
55 throw engine::WaitInterruptedException(
57 }
58}
59
60template <typename SubscribableFuture>
62 SubscribableFuture&& future, engine::Deadline deadline) {
63 auto event_holder = utils::make_intrusive_ptr<impl::EventHolder>();
64 future.Subscribe([event_holder](auto&) { event_holder->event.Send(); });
65 if (event_holder->event.WaitForEventUntil(deadline)) {
66 return engine::FutureStatus::kReady;
67 }
70}
71
72} // namespace drivers
73
74USERVER_NAMESPACE_END