/* This file is part of Telegram Desktop, the official desktop application for the Telegram messaging service. For license and copyright information please follow this link: https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once #include #include namespace rpl { namespace details { template struct supports_equality_compare { template static auto test(const U *u, const V *v) -> decltype(*u == *v, details::true_t()); static details::false_t test(...); static constexpr bool value = (sizeof(test( (std::decay_t*)nullptr, (std::decay_t*)nullptr )) == sizeof(details::true_t)); }; template constexpr bool supports_equality_compare_v = supports_equality_compare::value; } // namespace details template class variable final { public: variable() : _data{} { } template < typename OtherType, typename = std::enable_if_t< std::is_constructible_v>> variable(OtherType &&data) : _data(std::forward(data)) { } template < typename OtherType, typename = std::enable_if_t< std::is_assignable_v>> variable &operator=(OtherType &&data) { _lifetime.destroy(); return assign(std::forward(data)); } template < typename OtherType, typename Error, typename Generator, typename = std::enable_if_t< std::is_assignable_v>> variable(producer &&stream) { std::move(stream) | start_with_next([this](auto &&data) { assign(std::forward(data)); }, _lifetime); } template < typename OtherType, typename Error, typename Generator, typename = std::enable_if_t< std::is_assignable_v>> variable &operator=( producer &&stream) { _lifetime.destroy(); std::move(stream) | start_with_next([this](auto &&data) { assign(std::forward(data)); }, _lifetime); } Type current() const { return _data; } auto value() const { return _changes.events_starting_with_copy(_data); } auto changes() const { return _changes.events(); } private: template variable &assign(OtherType &&data) { if constexpr (details::supports_equality_compare_v) { if (!(_data == data)) { _data = std::forward(data); _changes.fire_copy(_data); } } else if constexpr (details::supports_equality_compare_v) { auto old = std::move(_data); _data = std::forward(data); if (!(_data == old)) { _changes.fire_copy(_data); } } else { _data = std::forward(data); _changes.fire_copy(_data); } return *this; } Type _data; event_stream _changes; lifetime _lifetime; }; } // namespace rpl