13#include <userver/compiler/demangle.hpp>
14#include <userver/components/component_fwd.hpp>
15#include <userver/components/impl/component_base.hpp>
16#include <userver/engine/task/task_processor_fwd.hpp>
18USERVER_NAMESPACE_BEGIN
20namespace engine::impl {
27class ComponentContext;
31enum class ComponentLifetimeStage;
33class ComponentContextImpl;
35using ComponentFactory =
36 std::function<std::unique_ptr<components::impl::ComponentBase>(
37 const components::ComponentContext&)>;
40constexpr auto NameFromComponentType() ->
decltype(std::string_view{T::kName}) {
44template <
class T,
class... Args>
45constexpr auto NameFromComponentType(Args...) {
46 static_assert(!
sizeof(T),
47 "Component does not have a 'kName' member convertible to "
48 "std::string_view. You have to explicitly specify the name: "
49 "context.FindComponent<T>(name) or "
50 "context.FindComponentOptional<T>(name).");
51 return std::string_view{};
60 ComponentsLoadCancelledException();
61 explicit ComponentsLoadCancelledException(
const std::string& message);
73class ComponentContext
final {
88 return FindComponent<T>(impl::NameFromComponentType<T>());
93 T& FindComponent(std::string_view name)
const {
94 if (!Contains(name)) {
95 ThrowNonRegisteredComponent(name, compiler::GetTypeName<T>());
98 auto* component_base = DoFindComponent(name);
99 T* ptr =
dynamic_cast<T*>(component_base);
101 ThrowComponentTypeMismatch(name, compiler::GetTypeName<T>(),
108 template <
typename T>
109 T& FindComponent(std::string_view = {}) {
110 return ReportMisuse<T>();
115 template <
typename T>
117 return FindComponentOptional<T>(impl::NameFromComponentType<T>());
121 template <
typename T>
122 T* FindComponentOptional(std::string_view name)
const {
123 if (!Contains(name)) {
126 return dynamic_cast<T*>(DoFindComponent(name));
129 template <
typename T>
130 T& FindComponentOptional(std::string_view = {}) {
131 return ReportMisuse<T>();
137 template <
typename T>
138 engine::TaskProcessor& GetTaskProcessor(
const T&) {
139 return ReportMisuse<T>();
142 const Manager& GetManager()
const;
147 bool Contains(std::string_view name)
const noexcept;
149 template <
typename T>
150 bool Contains(
const T&) {
151 return ReportMisuse<T>();
155 decltype(
auto) ReportMisuse() {
156 static_assert(!
sizeof(T),
157 "components::ComponentContext should be accepted by "
158 "a constant reference, i.e. "
159 "`MyComponent(const components::ComponentConfig& config, "
160 "const components::ComponentContext& context)`");
164 friend class Manager;
167 ComponentContext()
noexcept;
169 void Emplace(
const Manager& manager,
170 std::vector<std::string>&& loading_component_names);
172 void Reset()
noexcept;
176 impl::ComponentBase* AddComponent(std::string_view name,
177 const impl::ComponentFactory& factory);
179 void OnAllComponentsLoaded();
181 void OnAllComponentsAreStopping();
183 void ClearComponents();
185 void CancelComponentsLoad();
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;
193 impl::ComponentBase* DoFindComponent(std::string_view name)
const;
195 std::unique_ptr<impl::ComponentContextImpl> impl_;