/* 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 #include #include "base/optional.h" namespace rpl { namespace details { template class filter_helper { public: template filter_helper(OtherPredicate &&predicate) : _predicate(std::forward(predicate)) { } template < typename Value, typename Error, typename Generator, typename = std::enable_if_t< details::is_callable_v>> auto operator()(producer &&initial) { return make_producer([ initial = std::move(initial), predicate = std::move(_predicate) ](const auto &consumer) mutable { return std::move(initial).start( [ consumer, predicate = std::move(predicate) ](auto &&value) { const auto &immutable = value; if (details::callable_invoke( predicate, immutable) ) { consumer.put_next_forward( std::forward(value)); } }, [consumer](auto &&error) { consumer.put_error_forward( std::forward(error)); }, [consumer] { consumer.put_done(); }); }); } private: Predicate _predicate; }; } // namespace details template inline auto filter(Predicate &&predicate) -> details::filter_helper> { return details::filter_helper>( std::forward(predicate)); } namespace details { template class filter_helper> { public: filter_helper( producer &&filterer) : _filterer(std::move(filterer)) { } template auto operator()(producer &&initial) { using namespace mappers; return combine(std::move(initial), std::move(_filterer)) | filter(_2) | map(_1_of_two); } private: producer _filterer; }; template inline const Value &deref_optional_helper( const std::optional &value) { return *value; } template inline Value &&deref_optional_helper( std::optional &&value) { return std::move(*value); } class filter_optional_helper { public: template auto operator()(producer< std::optional, Error, Generator> &&initial) const { return make_producer([ initial = std::move(initial) ](const auto &consumer) mutable { return std::move(initial).start( [consumer](auto &&value) { if (value) { consumer.put_next_forward( deref_optional_helper( std::forward( value))); } }, [consumer](auto &&error) { consumer.put_error_forward( std::forward(error)); }, [consumer] { consumer.put_done(); }); }); } }; } // namespace details inline auto filter_optional() -> details::filter_optional_helper { return details::filter_optional_helper(); } } // namespace rpl