11#include <userver/concurrent/async_event_source.hpp>
12#include <userver/dynamic_config/snapshot.hpp>
13#include <userver/utils/assert.hpp>
15USERVER_NAMESPACE_BEGIN
17namespace dynamic_config {
21template <
typename VariableType>
22class VariableSnapshotPtr
final {
24 VariableSnapshotPtr(VariableSnapshotPtr&&) =
delete;
25 VariableSnapshotPtr& operator=(VariableSnapshotPtr&&) =
delete;
27 const VariableType& operator*()
const& {
return *variable_; }
28 const VariableType& operator*() && { ReportMisuse(); }
30 const VariableType* operator->()
const& {
return variable_; }
31 const VariableType* operator->() && { ReportMisuse(); }
34 [[noreturn]]
static void ReportMisuse() {
35 static_assert(!
sizeof(VariableType),
36 "keep the pointer before using, please");
39 explicit VariableSnapshotPtr(Snapshot&& snapshot,
40 const Key<VariableType>& key)
41 : snapshot_(std::move(snapshot)), variable_(&snapshot_[key]) {}
47 const VariableType* variable_;
58 std::optional<Snapshot> previous;
79 using SnapshotEventSource =
concurrent::AsyncEventSource<
const Snapshot&>;
80 using DiffEventSource =
concurrent::AsyncEventSource<
const Diff&>;
84 explicit Source(impl::StorageData& storage);
87 Source(
const Source&) =
default;
88 Source(Source&&) =
default;
89 Source& operator=(
const Source&) =
default;
90 Source& operator=(Source&&) =
default;
92 Snapshot GetSnapshot()
const;
94 template <
typename VariableType>
95 VariableSnapshotPtr<VariableType> GetSnapshot(
96 const Key<VariableType>& key)
const {
97 return VariableSnapshotPtr{GetSnapshot(), key};
100 template <
typename VariableType>
101 VariableType GetCopy(
const Key<VariableType>& 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),
202 const Keys&... keys) {
203 auto wrapper = [obj, func, keys = std::make_tuple(std::cref(keys)...)](
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,
const 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_;