userver: userver/utils/resource_scopes.hpp Source File
Loading...
Searching...
No Matches
resource_scopes.hpp
1#pragma once
2
3/// @file userver/utils/scope.hpp
4/// @brief @copybrief utils::ResourceScopeStorage
5
6#include <functional>
7#include <memory>
8#include <optional>
9
10#include <userver/components/component_fwd.hpp>
11#include <userver/utils/assert.hpp>
12#include <userver/utils/move_only_function.hpp>
13
14USERVER_NAMESPACE_BEGIN
15
16namespace utils {
17
18namespace impl {
19class ScopeBase {
20public:
21 virtual ~ScopeBase() = default;
22
23 virtual void AfterConstruction() = 0;
24};
25
26template <typename Handle>
27class Scope final : public ScopeBase {
28public:
29 using AfterConstructionCallback = utils::move_only_function<Handle()>;
30
31 explicit Scope(AfterConstructionCallback after_construction)
32 : after_construction_(std::move(after_construction))
33 {}
34
35 void AfterConstruction() override { before_destruction_.emplace(after_construction_()); }
36
37private:
38 AfterConstructionCallback after_construction_;
39 std::optional<Handle> before_destruction_;
40};
41
42template <>
43class Scope<void> final : public ScopeBase {
44public:
45 using AfterConstructionCallback = utils::move_only_function<void()>;
46
47 explicit Scope(AfterConstructionCallback after_construction)
48 : after_construction_(std::move(after_construction))
49 {}
50
51 void AfterConstruction() override { after_construction_(); }
52
53private:
54 AfterConstructionCallback after_construction_;
55};
56
57/// @brief An object of ScopePtr defines actions to do after
58/// a component is constructed and just before it is destroyed.
59///
60/// @see @ref components::ComponentContext::Scopes
61using ScopePtr = std::unique_ptr<impl::ScopeBase>;
62
63} // namespace impl
64
65/// @brief Smart collection of @ref ScopePtr.
66/// It is a helper class used in component system or in a component-less
67/// unit tests.
68class ResourceScopeStorage final {
69public:
70 /// @brief Registers a functor to register some resource that will be
71 /// called after the component is successfully created (including all
72 /// class descendants) or after the component creation is emulated in
73 /// unit tests. The functor must return a RAII-style handle object
74 /// that unregisters the previously registered resource. The returned handle's
75 /// destructor is called just before the component destructor is called.
76 ///
77 /// @note callback is not called if the component is not created OR
78 /// any previously registered callback throws an exception.
79 /// @note if you don't have an existing RAII-ish class, but still want
80 /// to do a cleanup, you might want to use @ref utils::FastScopeGuard
81 /// to wrap the cleanup function.
82 template <typename AfterConstructionCallback>
83 void Register(AfterConstructionCallback after_construction)
84 {
85 using Handle = std::invoke_result_t<AfterConstructionCallback>;
86 auto scope = std::make_unique<impl::Scope<Handle>>(std::move(after_construction));
87 DoRegister(std::move(scope));
88 }
89
90 /// @brief Call all registered functors.
92
93 /// @brief Free all unregister previously rgistered resources.
95
96private:
97 void DoRegister(impl::ScopePtr resource_scope);
98
99 std::vector<impl::ScopePtr> registered_scopes_;
100 std::vector<impl::ScopePtr> initialized_scopes_;
101 bool scope_registration_finished_{false};
102};
103
104ResourceScopeStorage&
105LocateDependency(components::WithType<ResourceScopeStorage>, const components::ComponentConfig& config, const components::ComponentContext&);
106
107} // namespace utils
108
109USERVER_NAMESPACE_END