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),
"keep the pointer before using, please");
37 explicit VariableSnapshotPtr(Snapshot&& snapshot,
const Key<VariableType>& key)
38 : snapshot_(std::move(snapshot)),
39 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(
const Key<VariableType>& key)
const {
95 return VariableSnapshotPtr{GetSnapshot(), key};
98 template <
typename VariableType>
99 VariableType GetCopy(
const Key<VariableType>& key)
const {
100 const auto snapshot = GetSnapshot();
101 return snapshot[key];
120 template <
typename Class>
123 std::string_view name,
124 void (Class::*func)(
const dynamic_config::Snapshot& config)
126 return DoUpdateAndListen(
129 [obj, func](
const dynamic_config::Snapshot& config) { (obj->*func)(config); }
166 template <
typename Class>
169 std::string_view name,
170 void (Class::*func)(
const dynamic_config::Diff& diff)
172 return DoUpdateAndListen(
concurrent::FunctionId(obj), name, [obj, func](
const dynamic_config::Diff& diff) {
200 template <
typename Class,
typename... Keys>
203 std::string_view name,
204 void (Class::*func)(
const dynamic_config::Snapshot& config),
207 auto wrapper = [obj, func, &keys...](
const Diff& diff) {
208 if (!HasChanged(diff, keys...)) {
211 (obj->*func)(diff.current);
213 return DoUpdateAndListen(
concurrent::FunctionId(obj), name, std::move(wrapper));
216 SnapshotEventSource& GetEventChannel();
219 template <
typename... Keys>
220 static bool HasChanged(
const Diff& diff,
const Keys&... keys) {
221 if (!diff.previous) {
225 const auto& previous = *diff.previous;
226 const auto& current = diff.current;
228 UASSERT(!current.GetData().IsEmpty());
229 UASSERT(!previous.GetData().IsEmpty());
231 const bool is_equal = (
true && ... && (previous[keys] == current[keys]));
235 concurrent::AsyncEventSubscriberScope DoUpdateAndListen(
237 std::string_view name,
238 SnapshotEventSource::Function&& func
241 concurrent::AsyncEventSubscriberScope DoUpdateAndListen(
243 std::string_view name,
244 DiffEventSource::Function&& func
247 impl::StorageData* storage_;