userver: userver/components/component_list.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
component_list.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/components/component_list.hpp
4/// @brief @copybrief components::ComponentList
5
6#include <functional>
7#include <memory>
8#include <set>
9#include <string>
10
11#include <userver/components/component_fwd.hpp>
12#include <userver/components/static_config_validator.hpp>
13
14USERVER_NAMESPACE_BEGIN
15
16namespace components {
17
18class Manager;
19
20namespace impl {
21
22template <class T>
23auto NameRegistrationFromComponentType() -> decltype(std::string{T::kName}) {
24 return std::string{T::kName};
25}
26
27template <class T, class... Args>
28auto NameRegistrationFromComponentType(Args...) {
29 static_assert(!sizeof(T),
30 "Component does not have a 'kName' member convertible to "
31 "std::string. You have to explicitly specify the name: "
32 "component_list.Append<T>(name).");
33 return std::string{};
34}
35
36using ComponentBaseFactory =
37 std::function<std::unique_ptr<components::impl::ComponentBase>(
38 const components::ComponentConfig&,
39 const components::ComponentContext&)>;
40
41// Hides manager implementation from header
42void AddComponentImpl(Manager& manager,
43 const components::ComponentConfigMap& config_map,
44 const std::string& name, ComponentBaseFactory factory);
45
46class ComponentAdderBase {
47 public:
48 ComponentAdderBase() = delete;
49 ComponentAdderBase(const ComponentAdderBase&) = delete;
50 ComponentAdderBase(ComponentAdderBase&&) = delete;
51 ComponentAdderBase& operator=(const ComponentAdderBase&) = delete;
52 ComponentAdderBase& operator=(ComponentAdderBase&&) = delete;
53
54 ComponentAdderBase(std::string name, ConfigFileMode config_file_mode);
55
56 virtual ~ComponentAdderBase();
57
58 const std::string& GetComponentName() const noexcept { return name_; }
59
60 ConfigFileMode GetConfigFileMode() const { return config_file_mode_; }
61
62 virtual void operator()(Manager&,
63 const components::ComponentConfigMap&) const = 0;
64
65 virtual void ValidateStaticConfig(const ComponentConfig&,
66 ValidationMode) const = 0;
67
68 virtual yaml_config::Schema GetStaticConfigSchema() const = 0;
69
70 private:
71 std::string name_;
72 ConfigFileMode config_file_mode_;
73};
74
75template <typename Component>
76class ComponentAdder final : public ComponentAdderBase {
77 public:
78 explicit ComponentAdder(std::string name)
79 : ComponentAdderBase(std::move(name), kConfigFileMode<Component>) {}
80
81 void operator()(Manager&,
82 const components::ComponentConfigMap&) const override;
83
84 void ValidateStaticConfig(const ComponentConfig& static_config,
85 ValidationMode validation_mode) const override {
86 impl::TryValidateStaticConfig<Component>(static_config, validation_mode);
87 }
88
89 yaml_config::Schema GetStaticConfigSchema() const override {
90 return impl::GetStaticConfigSchema<Component>();
91 }
92};
93
94template <typename Component>
95void ComponentAdder<Component>::operator()(
96 Manager& manager, const components::ComponentConfigMap& config_map) const {
97 // Using std::is_convertible_v because std::is_base_of_v returns true even
98 // if ComponentBase is a private, protected, or ambiguous base class.
99 static_assert(
100 std::is_convertible_v<Component*, components::impl::ComponentBase*>,
101 "Component should publicly inherit from components::LoggableComponentBase"
102 " and the component definition should be visible at its registration");
103 impl::AddComponentImpl(manager, config_map, GetComponentName(),
104 [](const components::ComponentConfig& config,
105 const components::ComponentContext& context) {
106 return std::make_unique<Component>(config, context);
107 });
108}
109
110using ComponentAdderPtr = std::unique_ptr<const impl::ComponentAdderBase>;
111
112struct ComponentAdderComparator {
113 using is_transparent = std::true_type;
114
115 static std::string_view ToStringView(const ComponentAdderPtr& x) noexcept {
116 return std::string_view{x->GetComponentName()};
117 }
118
119 static std::string_view ToStringView(std::string_view x) noexcept {
120 return x;
121 }
122
123 template <class T, class U>
124 bool operator()(const T& x, const U& y) const noexcept {
125 return ToStringView(x) < ToStringView(y);
126 }
127};
128
129} // namespace impl
130
131/// @brief A list to keep a unique list of components to start with
132/// components::Run(), utils::DaemonMain() or components::RunOnce().
133class ComponentList final {
134 public:
135 /// Appends a component with default component name Component::kName.
136 template <typename Component>
137 ComponentList& Append() &;
138
139 /// Appends a component with a provided component name.
140 template <typename Component>
141 ComponentList& Append(std::string name) &;
142
143 /// Merges components from `other` into `*this`.
144 ComponentList& AppendComponentList(ComponentList&& other) &;
145
146 /// @overload
147 ComponentList&& AppendComponentList(ComponentList&& other) &&;
148
149 /// @overload
150 template <typename Component, typename... Args>
151 ComponentList&& Append(Args&&...) &&;
152
153 /// @return true iff the component with provided name was added to *this.
154 bool Contains(std::string_view name) const { return adders_.count(name) > 0; }
155
156 /// @cond
157 using Adders =
158 std::set<impl::ComponentAdderPtr, impl::ComponentAdderComparator>;
159
160 Adders::const_iterator begin() const { return adders_.begin(); }
161 Adders::const_iterator end() const { return adders_.end(); }
162
163 ComponentList& Append(impl::ComponentAdderPtr&& added) &;
164
165 yaml_config::Schema GetStaticConfigSchema() const;
166
167 private:
168 Adders adders_;
169 /// @endcond
170};
171
172template <typename Component>
173ComponentList& ComponentList::Append() & {
174 return Append<Component>(
175 impl::NameRegistrationFromComponentType<Component>());
176}
177
178template <typename Component>
179ComponentList& ComponentList::Append(std::string name) & {
180 using Adder = impl::ComponentAdder<Component>;
181 auto adder = std::make_unique<const Adder>(std::move(name));
182 return Append(std::move(adder));
183}
184
185template <typename Component, typename... Args>
186ComponentList&& ComponentList::Append(Args&&... args) && {
187 return std::move(Append<Component>(std::forward<Args>(args)...));
188}
189
190} // namespace components
191
192USERVER_NAMESPACE_END