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 {
20template <
typename VariableType>
21class VariableSnapshotPtr
final {
23 VariableSnapshotPtr(VariableSnapshotPtr&&) =
delete;
24 VariableSnapshotPtr& operator=(VariableSnapshotPtr&&) =
delete;
26 const VariableType& operator*()
const& {
return *variable_; }
27 const VariableType& operator*() && { ReportMisuse(); }
29 const VariableType* operator->()
const& {
return variable_; }
30 const VariableType* operator->() && { ReportMisuse(); }
33 [[noreturn]]
static void ReportMisuse() {
34 static_assert(!
sizeof(VariableType),
35 "keep the pointer before using, please");
38 explicit VariableSnapshotPtr(Snapshot&& snapshot,
39 const Key<VariableType>& key)
40 : snapshot_(std::move(snapshot)), variable_(&snapshot_[key]) {}
46 const VariableType* variable_;
57 std::optional<Snapshot> previous;
78 using SnapshotEventSource =
concurrent::AsyncEventSource<
const Snapshot&>;
79 using DiffEventSource =
concurrent::AsyncEventSource<
const Diff&>;
83 explicit Source(impl::StorageData& storage);
86 Source(
const Source&) =
default;
87 Source(Source&&) =
default;
88 Source& operator=(
const Source&) =
default;
89 Source& operator=(Source&&) =
default;
91 Snapshot GetSnapshot()
const;
93 template <
typename VariableType>
94 VariableSnapshotPtr<VariableType> GetSnapshot(
95 const Key<VariableType>& key)
const {
96 return VariableSnapshotPtr{GetSnapshot(), key};
99 template <
typename VariableType>
100 VariableType GetCopy(
const Key<VariableType>& key)
const {
101 const auto snapshot = GetSnapshot();
102 return snapshot[key];
121 template <
typename Class>
123 Class* obj, std::string_view name,
124 void (Class::*func)(
const dynamic_config::Snapshot& config)) {
125 return DoUpdateAndListen(
126 concurrent::FunctionId(obj), name,
127 [obj, func](
const dynamic_config::Snapshot& config) {
128 (obj->*func)(config);
165 template <
typename Class>
167 Class* obj, std::string_view name,
168 void (Class::*func)(
const dynamic_config::Diff& diff)) {
169 return DoUpdateAndListen(
170 concurrent::FunctionId(obj), name,
171 [obj, func](
const dynamic_config::Diff& diff) { (obj->*func)(diff); });
197 template <
typename Class,
typename... Keys>
199 Class* obj, std::string_view name,
200 void (Class::*func)(
const dynamic_config::Snapshot& config),
201 const Keys&... keys) {
202 auto wrapper = [obj, func, &keys...](
const Diff& diff) {
203 if (!HasChanged(diff, keys...))
return;
204 (obj->*func)(diff.current);
206 return DoUpdateAndListen(concurrent::FunctionId(obj), name,
210 SnapshotEventSource& GetEventChannel();
213 template <
typename... Keys>
214 static bool HasChanged(
const Diff& diff,
const Keys&... keys) {
215 if (!diff.previous)
return true;
217 const auto& previous = *diff.previous;
218 const auto& current = diff.current;
220 UASSERT(!current.GetData().IsEmpty());
221 UASSERT(!previous.GetData().IsEmpty());
223 const bool is_equal = (
true && ... && (previous[keys] == current[keys]));
227 concurrent::AsyncEventSubscriberScope DoUpdateAndListen(
228 concurrent::FunctionId id, std::string_view name,
229 SnapshotEventSource::Function&& func);
231 concurrent::AsyncEventSubscriberScope DoUpdateAndListen(
232 concurrent::FunctionId id, std::string_view name,
233 DiffEventSource::Function&& func);
235 impl::StorageData* storage_;