13#include <userver/compiler/demangle.hpp>
14#include <userver/components/impl/component_base.hpp>
15#include <userver/engine/task/task_processor_fwd.hpp>
17USERVER_NAMESPACE_BEGIN
19namespace engine::impl {
29enum class ComponentLifetimeStage;
33constexpr auto NameFromComponentType() ->
decltype(std::string_view{T::kName}) {
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{};
53 ComponentsLoadCancelledException();
54 explicit ComponentsLoadCancelledException(
const std::string& message);
64class ComponentContext
final {
79 return FindComponent<T>(impl::NameFromComponentType<T>());
84 T& FindComponent(std::string_view name)
const {
85 if (!Contains(name)) {
86 ThrowNonRegisteredComponent(name, compiler::GetTypeName<T>());
89 auto* component_base = DoFindComponent(name);
90 T* ptr =
dynamic_cast<T*>(component_base);
92 ThrowComponentTypeMismatch(name, compiler::GetTypeName<T>(),
100 T& FindComponent(std::string_view = {}) {
101 return ReportMisuse<T>();
106 template <
typename T>
108 return FindComponentOptional<T>(impl::NameFromComponentType<T>());
112 template <
typename T>
113 T* FindComponentOptional(std::string_view name)
const {
114 if (!Contains(name)) {
117 return dynamic_cast<T*>(DoFindComponent(name));
120 template <
typename T>
121 T& FindComponentOptional(std::string_view = {}) {
122 return ReportMisuse<T>();
128 template <
typename T>
129 engine::TaskProcessor& GetTaskProcessor(
const T&) {
130 return ReportMisuse<T>();
133 const Manager& GetManager()
const;
144 bool Contains(std::string_view name)
const noexcept;
146 template <
typename T>
147 bool Contains(
const T&) {
148 return ReportMisuse<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)`");
161 friend class Manager;
163 ComponentContext()
noexcept;
165 void Emplace(
const Manager& manager,
166 std::vector<std::string>&& loading_component_names);
168 void Reset()
noexcept;
172 using ComponentFactory =
173 std::function<std::unique_ptr<components::impl::ComponentBase>(
174 const components::ComponentContext&)>;
176 impl::ComponentBase* AddComponent(std::string_view name,
177 const 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;
196 std::unique_ptr<Impl> impl_;