10#include <userver/concurrent/async_event_source.hpp>
11#include <userver/dynamic_config/snapshot.hpp>
12#include <userver/utils/assert.hpp>
14USERVER_NAMESPACE_BEGIN
16namespace dynamic_config {
24template <
typename Key>
25class VariableSnapshotPtr
final {
27 VariableSnapshotPtr(VariableSnapshotPtr&&) =
delete;
28 VariableSnapshotPtr& operator=(VariableSnapshotPtr&&) =
delete;
30 const VariableOfKey<Key>& operator*()
const& {
return variable_; }
31 const VariableOfKey<Key>& operator*() && { ReportMisuse(); }
33 const VariableOfKey<Key>* operator->()
const& {
return &variable_; }
34 const VariableOfKey<Key>* operator->() && { ReportMisuse(); }
37 [[noreturn]]
static void ReportMisuse() {
38 static_assert(!
sizeof(Key),
"keep the pointer before using, please");
41 explicit VariableSnapshotPtr(Snapshot&& snapshot, Key key)
42 : snapshot_(std::move(snapshot)), variable_(snapshot_[key]) {}
48 const VariableOfKey<Key>& variable_;
59 std::optional<Snapshot> previous;
80 using SnapshotEventSource =
concurrent::AsyncEventSource<
const Snapshot&>;
81 using DiffEventSource =
concurrent::AsyncEventSource<
const Diff&>;
85 explicit Source(impl::StorageData& storage);
88 Source(
const Source&) =
default;
89 Source(Source&&) =
default;
90 Source& operator=(
const Source&) =
default;
91 Source& operator=(Source&&) =
default;
93 Snapshot GetSnapshot()
const;
95 template <
typename Key>
96 VariableSnapshotPtr<Key> GetSnapshot(Key key)
const {
97 return VariableSnapshotPtr{GetSnapshot(), key};
100 template <
typename Key>
101 VariableOfKey<Key> GetCopy(Key key)
const {
102 const auto snapshot = GetSnapshot();
103 return snapshot[key];
122 template <
typename Class>
124 Class* obj, std::string_view name,
125 void (Class::*func)(
const dynamic_config::Snapshot& config)) {
126 return DoUpdateAndListen(
127 concurrent::FunctionId(obj), name,
128 [obj, func](
const dynamic_config::Snapshot& config) {
129 (obj->*func)(config);
166 template <
typename Class>
168 Class* obj, std::string_view name,
169 void (Class::*func)(
const dynamic_config::Diff& diff)) {
170 return DoUpdateAndListen(
171 concurrent::FunctionId(obj), name,
172 [obj, func](
const dynamic_config::Diff& diff) { (obj->*func)(diff); });
198 template <
typename Class,
typename... Keys>
200 Class* obj, std::string_view name,
201 void (Class::*func)(
const dynamic_config::Snapshot& config),
203 auto wrapper = [obj, func,
204 keys = std::make_tuple(keys...)](
const Diff& diff) {
205 const auto args = std::tuple_cat(std::tie(diff), keys);
206 if (!std::apply(HasChanged<Keys...>, args))
return;
207 (obj->*func)(diff.current);
209 return DoUpdateAndListen(concurrent::FunctionId(obj), name,
213 SnapshotEventSource& GetEventChannel();
216 template <
typename... Keys>
217 static bool HasChanged(
const Diff& diff, Keys... keys) {
218 if (!diff.previous)
return true;
220 const auto& previous = *diff.previous;
221 const auto& current = diff.current;
223 UASSERT(!current.GetData().IsEmpty());
224 UASSERT(!previous.GetData().IsEmpty());
226 const bool is_equal = (
true && ... && (previous[keys] == current[keys]));
230 concurrent::AsyncEventSubscriberScope DoUpdateAndListen(
231 concurrent::FunctionId id, std::string_view name,
232 SnapshotEventSource::Function&& func);
234 concurrent::AsyncEventSubscriberScope DoUpdateAndListen(
235 concurrent::FunctionId id, std::string_view name,
236 DiffEventSource::Function&& func);
238 impl::StorageData* storage_;