Github   Telegram
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 private:
69 std::string name_;
70 ConfigFileMode config_file_mode_;
71};
72
73template <typename Component>
74class ComponentAdder final : public ComponentAdderBase {
75 public:
76 explicit ComponentAdder(std::string name)
77 : ComponentAdderBase(std::move(name), kConfigFileMode<Component>) {}
78
79 void operator()(Manager&,
80 const components::ComponentConfigMap&) const override;
81
82 void ValidateStaticConfig(const ComponentConfig& static_config,
83 ValidationMode validation_mode) const override {
84 impl::TryValidateStaticConfig<Component>(static_config, validation_mode);
85 }
86};
87
88template <typename Component>
89void ComponentAdder<Component>::operator()(
90 Manager& manager, const components::ComponentConfigMap& config_map) const {
91 // Using std::is_convertible_v because std::is_base_of_v returns true even
92 // if ComponentBase is a private, protected, or ambiguous base class.
93 static_assert(
94 std::is_convertible_v<Component*, components::impl::ComponentBase*>,
95 "Component should publicly inherit from components::LoggableComponentBase"
96 " and the component definition should be visible at its registration");
97 impl::AddComponentImpl(manager, config_map, GetComponentName(),
98 [](const components::ComponentConfig& config,
99 const components::ComponentContext& context) {
100 return std::make_unique<Component>(config, context);
101 });
102}
103
104using ComponentAdderPtr = std::unique_ptr<const impl::ComponentAdderBase>;
105
106struct ComponentAdderComparator {
107 using is_transparent = std::true_type;
108
109 static std::string_view ToStringView(const ComponentAdderPtr& x) noexcept {
110 return std::string_view{x->GetComponentName()};
111 }
112
113 static std::string_view ToStringView(std::string_view x) noexcept {
114 return x;
115 }
116
117 template <class T, class U>
118 bool operator()(const T& x, const U& y) const noexcept {
119 return ToStringView(x) < ToStringView(y);
120 }
121};
122
123} // namespace impl
124
125/// @brief A list to keep a unique list of components to start with
126/// components::Run(), utils::DaemonMain() or components::RunOnce().
127class ComponentList final {
128 public:
129 /// Appends a component with default component name Component::kName.
130 template <typename Component>
131 ComponentList& Append() &;
132
133 /// Appends a component with a provided component name.
134 template <typename Component>
135 ComponentList& Append(std::string name) &;
136
137 /// Merges components from `other` into `*this`.
138 ComponentList& AppendComponentList(ComponentList&& other) &;
139
140 /// @overload
141 ComponentList&& AppendComponentList(ComponentList&& other) &&;
142
143 /// @overload
144 template <typename Component, typename... Args>
145 ComponentList&& Append(Args&&...) &&;
146
147 /// @return true iff the component with provided name was added to *this.
148 bool Contains(std::string_view name) const { return adders_.count(name) > 0; }
149
150 /// @cond
151 using Adders =
152 std::set<impl::ComponentAdderPtr, impl::ComponentAdderComparator>;
153
154 Adders::const_iterator begin() const { return adders_.begin(); }
155 Adders::const_iterator end() const { return adders_.end(); }
156
157 ComponentList& Append(impl::ComponentAdderPtr&& added) &;
158
159 private:
160 Adders adders_;
161 /// @endcond
162};
163
164template <typename Component>
165ComponentList& ComponentList::Append() & {
166 return Append<Component>(
167 impl::NameRegistrationFromComponentType<Component>());
168}
169
170template <typename Component>
171ComponentList& ComponentList::Append(std::string name) & {
172 using Adder = impl::ComponentAdder<Component>;
173 auto adder = std::make_unique<const Adder>(std::move(name));
174 return Append(std::move(adder));
175}
176
177template <typename Component, typename... Args>
178ComponentList&& ComponentList::Append(Args&&... args) && {
179 return std::move(Append<Component>(std::forward<Args>(args)...));
180}
181
182} // namespace components
183
184USERVER_NAMESPACE_END