// // 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; template struct either_left; template struct either_left<::either> { using type = T; }; template using either_left_t = typename either_left::type; template class either_stream<::either> { private: template using map_f = decltype(std::declval()(std::declval())); template using flatmap_f = either_left_t>; 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<::either, E>> map(F && fun) const { using next_t = either_stream<::either, E>>; return value_.index() == 0 ? next_t{fun(std::get<0>(value_))} : next_t{std::get<1>(value_)}; } template either_stream<::either, E>> flatmap(F && fun) const { using next_t = either_stream<::either, E>>; return value_.index() == 0 ? next_t{fun(std::get<0>(value_))} : next_t{std::get<1>(value_)}; } template >::value && std::is_void>::value)>::type> typename std::common_type, map_f>::type match(FT && left, FE && right) { return value_.index() == 0 ? left(std::get<0>(value_)) : right(std::get<1>(value_)); } template >::value && std::is_void>::value>::type> void match(FT && left, FE && right) { value_.index() == 0 ? left(std::get<0>(value_)) : right(std::get<1>(value_)); } ::either const & value() const { return value_; } }; } namespace stream { namespace either { /** * Construct a stream from the given type while explicitly providing both the * type and the error class */ template auto make_stream(T const & opt) -> either_stream<::either> { return {{opt}}; } /** * Construct a stream from the given type where the real type is an inferred * property */ template auto make_stream(T const & opt) -> either_stream<::either> { return {{opt}}; } /** * Construct a stream with the given either-type as a template parameter. */ template auto make_stream(either_left_t const & opt) -> either_stream { return {{opt}}; } }}