/* 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 namespace rpl { namespace details { template < typename Transform, typename NewValue, typename Error, typename Handlers> class map_transform_helper { public: map_transform_helper( Transform &&transform, const consumer &consumer) : _consumer(consumer) , _transform(std::move(transform)) { } template < typename OtherValue, typename = std::enable_if_t< std::is_rvalue_reference_v>> void operator()(OtherValue &&value) const { _consumer.put_next_forward( details::callable_invoke(_transform, std::move(value))); } template < typename OtherValue, typename = decltype( std::declval()(const_ref_val()))> void operator()(const OtherValue &value) const { _consumer.put_next_forward( details::callable_invoke(_transform, value)); } private: consumer _consumer; Transform _transform; }; template < typename Transform, typename NewValue, typename Error, typename Handlers, typename = std::enable_if_t< std::is_rvalue_reference_v>> inline map_transform_helper map_transform( Transform &&transform, const consumer &consumer) { return { std::move(transform), consumer }; } template class map_helper { public: template map_helper(OtherTransform &&transform) : _transform(std::forward(transform)) { } template < typename Value, typename Error, typename Generator, typename NewValue = details::callable_result< Transform, Value>> auto operator()(producer &&initial) { return make_producer([ initial = std::move(initial), transform = std::move(_transform) ](const auto &consumer) mutable { return std::move(initial).start( map_transform( std::move(transform), consumer ), [consumer](auto &&error) { consumer.put_error_forward( std::forward(error)); }, [consumer] { consumer.put_done(); }); }); } private: Transform _transform; }; } // namespace details template inline auto map(Transform &&transform) -> details::map_helper> { return details::map_helper>( std::forward(transform)); } namespace details { template < typename Transform, typename Value, typename NewError, typename Handlers> class map_error_transform_helper { public: map_error_transform_helper( Transform &&transform, const consumer &consumer) : _transform(std::move(transform)) , _consumer(consumer) { } template < typename OtherError, typename = std::enable_if_t< std::is_rvalue_reference_v>> void operator()(OtherError &&error) const { _consumer.put_error_forward( details::callable_invoke(_transform, std::move(error))); } template < typename OtherError, typename = decltype( std::declval()(const_ref_val()))> void operator()(const OtherError &error) const { _consumer.put_error_forward( details::callable_invoke(_transform, error)); } private: consumer _consumer; Transform _transform; }; template < typename Transform, typename Value, typename NewError, typename Handlers, typename = std::enable_if_t< std::is_rvalue_reference_v>> inline map_error_transform_helper map_error_transform( Transform &&transform, const consumer &consumer) { return { std::move(transform), consumer }; } template class map_error_helper { public: template map_error_helper(OtherTransform &&transform) : _transform(std::forward(transform)) { } template < typename Value, typename Error, typename Generator, typename NewError = details::callable_result< Transform, Error>> auto operator()(producer &&initial) { return make_producer([ initial = std::move(initial), transform = std::move(_transform) ](const auto &consumer) mutable { return std::move(initial).start( [consumer](auto &&value) { consumer.put_next_forward( std::forward(value)); }, map_error_transform( std::move(transform), consumer ), [consumer] { consumer.put_done(); }); }); } private: Transform _transform; }; } // namespace details template inline auto map_error(Transform &&transform) -> details::map_error_helper> { return details::map_error_helper>( std::forward(transform)); } } // namespace rpl