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