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