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_;