userver: userver/components/component_context.hpp Source File
Loading...
Searching...
No Matches
component_context.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/components/component_context.hpp
4/// @brief @copybrief components::ComponentContext
5
6#include <functional>
7#include <memory>
8#include <stdexcept>
9#include <string>
10#include <string_view>
11#include <vector>
12
13#include <userver/compiler/demangle.hpp>
14#include <userver/components/impl/component_base.hpp>
15#include <userver/engine/task/task_processor_fwd.hpp>
16
17USERVER_NAMESPACE_BEGIN
18
19namespace engine::impl {
20class TaskContext;
21} // namespace engine::impl
22
23namespace components {
24
25class Manager;
26
27namespace impl {
28
29enum class ComponentLifetimeStage;
30class ComponentInfo;
31
32template <class T>
33constexpr auto NameFromComponentType() -> decltype(std::string_view{T::kName}) {
34 return T::kName;
35}
36
37template <class T, class... Args>
38constexpr auto NameFromComponentType(Args...) {
39 static_assert(!sizeof(T),
40 "Component does not have a 'kName' member convertible to "
41 "std::string_view. You have to explicitly specify the name: "
42 "context.FindComponent<T>(name) or "
43 "context.FindComponentOptional<T>(name).");
44 return std::string_view{};
45}
46
47} // namespace impl
48
49/// @brief Exception that is thrown from
50/// components::ComponentContext::FindComponent() if a component load failed.
51class ComponentsLoadCancelledException : public std::runtime_error {
52 public:
53 ComponentsLoadCancelledException();
54 explicit ComponentsLoadCancelledException(const std::string& message);
55};
56
57/// @brief Class to retrieve other components.
58///
59/// Only the const member functions of this class are meant for usage in
60/// component constructor (because of that this class is always passed as a
61/// const reference to the constructors).
62///
63/// @see @ref userver_components
64class ComponentContext final {
65 public:
66 /// @brief Finds a component of type T with specified name (if any) and
67 /// returns the component after it was initialized.
68 ///
69 /// Can only be called from other component's constructor in a task where
70 /// that constructor was called.
71 /// May block and asynchronously wait for the creation of the requested
72 /// component.
73 /// @throw ComponentsLoadCancelledException if components loading was
74 /// cancelled due to errors in the creation of other component.
75 /// @throw std::runtime_error if component missing in `component_list` was
76 /// requested.
77 template <typename T>
78 T& FindComponent() const {
79 return FindComponent<T>(impl::NameFromComponentType<T>());
80 }
81
82 /// @overload T& FindComponent()
83 template <typename T>
84 T& FindComponent(std::string_view name) const {
85 if (!Contains(name)) {
86 ThrowNonRegisteredComponent(name, compiler::GetTypeName<T>());
87 }
88
89 auto* component_base = DoFindComponent(name);
90 T* ptr = dynamic_cast<T*>(component_base);
91 if (!ptr) {
92 ThrowComponentTypeMismatch(name, compiler::GetTypeName<T>(),
93 component_base);
94 }
95
96 return *ptr;
97 }
98
99 template <typename T>
100 T& FindComponent(std::string_view /*name*/ = {}) {
101 return ReportMisuse<T>();
102 }
103
104 /// @brief If there's no component with specified type and name return
105 /// nullptr; otherwise behaves as FindComponent().
106 template <typename T>
108 return FindComponentOptional<T>(impl::NameFromComponentType<T>());
109 }
110
111 /// @overload T* FindComponentOptional()
112 template <typename T>
113 T* FindComponentOptional(std::string_view name) const {
114 if (!Contains(name)) {
115 return nullptr;
116 }
117 return dynamic_cast<T*>(DoFindComponent(name));
118 }
119
120 template <typename T>
121 T& FindComponentOptional(std::string_view /*name*/ = {}) {
122 return ReportMisuse<T>();
123 }
124
125 /// @brief Returns an engine::TaskProcessor with the specified name.
126 engine::TaskProcessor& GetTaskProcessor(const std::string& name) const;
127
128 template <typename T>
129 engine::TaskProcessor& GetTaskProcessor(const T&) {
130 return ReportMisuse<T>();
131 }
132
133 const Manager& GetManager() const;
134
135 /// @returns true if one of the components is in fatal state and can not
136 /// work. A component is in fatal state if the
137 /// components::ComponentHealth::kFatal value is returned from the overridden
138 /// components::LoggableComponentBase::GetComponentHealth().
140
141 private:
142 /// @returns true if there is a component with the specified name and it
143 /// could be found via FindComponent()
144 bool Contains(std::string_view name) const noexcept;
145
146 template <typename T>
147 bool Contains(const T&) {
148 return ReportMisuse<T>();
149 }
150
151 template <class T>
152 decltype(auto) ReportMisuse() {
153 static_assert(!sizeof(T),
154 "components::ComponentContext should be accepted by "
155 "a constant reference, i.e. "
156 "`MyComponent(const components::ComponentConfig& config, "
157 "const components::ComponentContext& context)`");
158 return 0;
159 }
160
161 friend class Manager;
162
163 ComponentContext() noexcept;
164
165 void Emplace(const Manager& manager,
166 std::vector<std::string>&& loading_component_names);
167
168 void Reset() noexcept;
169
170 ~ComponentContext();
171
172 using ComponentFactory =
173 std::function<std::unique_ptr<components::impl::ComponentBase>(
174 const components::ComponentContext&)>;
175
176 impl::ComponentBase* AddComponent(std::string_view name,
177 const ComponentFactory& factory);
178
179 void OnAllComponentsLoaded();
180
181 void OnAllComponentsAreStopping();
182
183 void ClearComponents();
184
185 void CancelComponentsLoad();
186
187 [[noreturn]] void ThrowNonRegisteredComponent(std::string_view name,
188 std::string_view type) const;
189 [[noreturn]] void ThrowComponentTypeMismatch(
190 std::string_view name, std::string_view type,
191 impl::ComponentBase* component) const;
192
193 impl::ComponentBase* DoFindComponent(std::string_view name) const;
194
195 struct Impl;
196 std::unique_ptr<Impl> impl_;
197};
198
199} // namespace components
200
201USERVER_NAMESPACE_END