// // either_stream.hpp // optional.stream // // Created by Sam Jaffe on 1/28/17. // #pragma once #include #include template using either = std::variant; namespace stream { template class either_stream; } namespace stream::traits { template struct either_traits; template struct either_traits<::either> { using stream_type = either_stream; using value_type = T; using error_type = E; }; template using either_stream_t = typename either_traits::stream_type; template using either_value_t = typename either_traits::value_type; } namespace stream { template class either_stream { private: template using map_f = decltype(std::declval()(std::declval())); template using flatmap_f = traits::either_value_t>; template inline static constexpr bool is_consumer_v = std::is_void_v> && std::is_void_v>; private: ::either value_; public: either_stream(E const & v) : value_(v) {} either_stream(E && v) : value_(std::forward(v)) {} either_stream(T const & v) : value_(v) {} either_stream(T && v) : value_(std::forward(v)) {} either_stream(::either const & v) : value_(v) {} either_stream(::either && v) : value_(std::forward<::either>(v)) {} template either_stream, E> map(F && fun) const { if (value_.index() == 0) { return fun(std::get<0>(value_)); } else { return std::get<1>(value_); } } template either_stream, E> flatmap(F && fun) const { if (value_.index() == 0) { return fun(std::get<0>(value_)); } else { return std::get<1>(value_); } } template auto match(FT && left, FE && right) -> std::common_type_t, map_f> { if (value_.index() == 0) { return left(std::get<0>(value_)); } else { return right(std::get<1>(value_)); } } ::either const & value() const { return value_; } }; } namespace stream::either { /** * Construct a stream from the given type while explicitly providing both the * type and the error class */ template either_stream make_stream(T const & opt) { return {{opt}}; } /** * Construct a stream from the given type where the real type is an inferred * property */ template either_stream make_stream(T const & opt) { return {{opt}}; } /** * Construct a stream with the given either-type as a template parameter. */ template auto make_stream(traits::either_value_t const & opt) { return traits::either_stream_t{opt}; } }