// This file is part of Desktop App Toolkit, // a set of libraries for developing nice desktop applications. // // For license and copyright information please follow this link: // https://github.com/desktop-app/legal/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 = std::remove_reference_t< details::callable_result>> 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)); } template [[nodiscard]] inline auto map_to(Value &&value) { return map([value = std::forward(value)] { return value; }); } inline auto to_empty = map_to(empty_value()); 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 = std::remove_reference_t< details::callable_result>> 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; }; class map_error_to_done_helper { public: map_error_to_done_helper() { } template < typename Value, typename Error, typename Generator> auto operator()(producer &&initial) { return make_producer([ initial = std::move(initial) ](const auto &consumer) mutable { return std::move(initial).start( [consumer](auto &&value) { consumer.put_next_forward( std::forward(value)); }, [consumer] { consumer.put_done(); }, [consumer] { consumer.put_done(); }); }); } }; } // namespace details template inline auto map_error(Transform &&transform) -> details::map_error_helper> { return details::map_error_helper>( std::forward(transform)); } inline details::map_error_to_done_helper map_error_to_done() { return details::map_error_to_done_helper(); } } // namespace rpl