userver: userver/components/component_list.hpp Source File
Loading...
Searching...
No Matches
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 /// @endcond
167
168 private:
169 Adders adders_;
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