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