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)), variable_(&snapshot_[key]) {}
44 const VariableType* variable_;
55 std::optional<Snapshot> previous;
76 using SnapshotEventSource =
concurrent::AsyncEventSource<
const Snapshot&>;
77 using DiffEventSource =
concurrent::AsyncEventSource<
const Diff&>;
81 explicit Source(impl::StorageData& storage);
84 Source(
const Source&) =
default;
85 Source(Source&&) =
default;
86 Source& operator=(
const Source&) =
default;
87 Source& operator=(Source&&) =
default;
89 Snapshot GetSnapshot()
const;
91 template <
typename VariableType>
92 VariableSnapshotPtr<VariableType> GetSnapshot(
const Key<VariableType>& key)
const {
93 return VariableSnapshotPtr{GetSnapshot(), key};
96 template <
typename VariableType>
97 VariableType GetCopy(
const Key<VariableType>& key)
const {
98 const auto snapshot = GetSnapshot();
118 template <
typename Class>
120 UpdateAndListen(Class* obj, std::string_view name,
void (Class::*func)(
const dynamic_config::Snapshot& config)) {
121 return DoUpdateAndListen(
122 concurrent::FunctionId(obj),
124 [obj, func](
const dynamic_config::Snapshot& config) { (obj->*func)(config); }
161 template <
typename Class>
163 UpdateAndListen(Class* obj, std::string_view name,
void (Class::*func)(
const dynamic_config::Diff& diff)) {
164 return DoUpdateAndListen(concurrent::FunctionId(obj), name, [obj, func](
const dynamic_config::Diff& diff) {
192 template <
typename Class,
typename... Keys>
195 std::string_view name,
196 void (Class::*func)(
const dynamic_config::Snapshot& config),
199 auto wrapper = [obj, func, &keys...](
const Diff& diff) {
200 if (!HasChanged(diff, keys...))
return;
201 (obj->*func)(diff.current);
203 return DoUpdateAndListen(concurrent::FunctionId(obj), name, std::move(wrapper));
206 SnapshotEventSource& GetEventChannel();
209 template <
typename... Keys>
210 static bool HasChanged(
const Diff& diff,
const Keys&... keys) {
211 if (!diff.previous)
return true;
213 const auto& previous = *diff.previous;
214 const auto& current = diff.current;
216 UASSERT(!current.GetData().IsEmpty());
217 UASSERT(!previous.GetData().IsEmpty());
219 const bool is_equal = (
true && ... && (previous[keys] == current[keys]));
224 DoUpdateAndListen(
concurrent::FunctionId id, std::string_view name, SnapshotEventSource::Function&& func);
227 DoUpdateAndListen(
concurrent::FunctionId id, std::string_view name, DiffEventSource::Function&& func);
229 impl::StorageData* storage_;