|
|
@@ -17,9 +17,12 @@ namespace stream {
|
|
|
}
|
|
|
|
|
|
namespace stream::traits {
|
|
|
+ template <typename Either> struct either_traits {
|
|
|
+ static constexpr bool const is_either = false;
|
|
|
+ };
|
|
|
|
|
|
- template <typename Either> struct either_traits;
|
|
|
template <typename T, typename E> struct either_traits<::either<T, E>> {
|
|
|
+ static constexpr bool const is_either = true;
|
|
|
using stream_type = either_stream<T, E>;
|
|
|
using value_type = T;
|
|
|
using error_type = E;
|
|
|
@@ -29,6 +32,8 @@ namespace stream::traits {
|
|
|
using either_stream_t = typename either_traits<Either>::stream_type;
|
|
|
template <typename Either>
|
|
|
using either_value_t = typename either_traits<Either>::value_type;
|
|
|
+ template <typename Either>
|
|
|
+ inline constexpr bool is_either_v = either_traits<Either>::is_either;
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -37,14 +42,7 @@ namespace stream {
|
|
|
template <typename T, typename E> class either_stream {
|
|
|
private:
|
|
|
template <typename F, typename T2 = T>
|
|
|
- using map_f = decltype(std::declval<F>()(std::declval<T2>()));
|
|
|
-
|
|
|
- template <typename F, typename T2 = T>
|
|
|
- using flatmap_f = traits::either_value_t<map_f<F, T2>>;
|
|
|
-
|
|
|
- template <typename FT, typename FE>
|
|
|
- inline static constexpr bool is_consumer_v =
|
|
|
- std::is_void_v<map_f<FT, T>> && std::is_void_v<map_f<FE, E>>;
|
|
|
+ using result_of = decltype(std::declval<F>()(std::declval<T2>()));
|
|
|
|
|
|
private:
|
|
|
::either<T, E> value_;
|
|
|
@@ -59,7 +57,9 @@ namespace stream {
|
|
|
either_stream(::either<T, E> && v)
|
|
|
: value_(std::forward<::either<T, E>>(v)) {}
|
|
|
|
|
|
- template <typename F> either_stream<map_f<F>, E> map(F && fun) const {
|
|
|
+ template <typename F>
|
|
|
+ auto map(F && fun) const -> either_stream<result_of<F>, E> {
|
|
|
+ static_assert(!traits::is_either_v<result_of<F>>, "Cannot nest eithers");
|
|
|
if (value_.index() == 0) {
|
|
|
return fun(std::get<0>(value_));
|
|
|
} else {
|
|
|
@@ -68,7 +68,8 @@ namespace stream {
|
|
|
}
|
|
|
|
|
|
template <typename F>
|
|
|
- either_stream<flatmap_f<F>, E> flatmap(F && fun) const {
|
|
|
+ auto flatmap(F && fun) const
|
|
|
+ -> either_stream<traits::either_value_t<result_of<F>>, E> {
|
|
|
if (value_.index() == 0) {
|
|
|
return fun(std::get<0>(value_));
|
|
|
} else {
|
|
|
@@ -78,7 +79,7 @@ namespace stream {
|
|
|
|
|
|
template <typename FT, typename FE>
|
|
|
auto match(FT && left, FE && right)
|
|
|
- -> std::common_type_t<map_f<FT, T>, map_f<FE, E>> {
|
|
|
+ -> std::common_type_t<result_of<FT, T>, result_of<FE, E>> {
|
|
|
if (value_.index() == 0) {
|
|
|
return left(std::get<0>(value_));
|
|
|
} else {
|