|
|
@@ -39,6 +39,21 @@ namespace stream::traits {
|
|
|
|
|
|
namespace stream {
|
|
|
|
|
|
+ /**
|
|
|
+ * An either stream is an object that allows functional compositions on a type
|
|
|
+ * that is either a concrete value or an error-type. This can be used as an
|
|
|
+ * alternative to the "status and out-param" pattern or exception-throwing
|
|
|
+ * code. It combines the benefits of both types - gaining the immediate
|
|
|
+ * knowledge of error-information that is provided by the first, while also
|
|
|
+ * allowing you to avoid out-params.
|
|
|
+ * The weakness of this design is that it often requires remodeling your
|
|
|
+ * entire codebase to operate around the either_stream. In order to terminate
|
|
|
+ * the stream, a fail-fast option is provided with operator bool(). However,
|
|
|
+ * the primary intent is to chain together functions with map and flatmap
|
|
|
+ * until you either have the desired result, or an error. At that point, you
|
|
|
+ * invoke match and handle the error with a default return value, an
|
|
|
+ * error-handler callback, or a thrown exception.
|
|
|
+ */
|
|
|
template <typename T, typename E> class either_stream {
|
|
|
private:
|
|
|
template <typename F, typename T2 = T>
|
|
|
@@ -57,10 +72,13 @@ namespace stream {
|
|
|
either_stream(::either<T, E> && v)
|
|
|
: value_(std::forward<::either<T, E>>(v)) {}
|
|
|
|
|
|
+ // This probably should be for internal use only
|
|
|
+ operator bool() const { return value_.index() == 0; }
|
|
|
+
|
|
|
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) {
|
|
|
+ if (*this) {
|
|
|
return fun(std::get<0>(value_));
|
|
|
} else {
|
|
|
return std::get<1>(value_);
|
|
|
@@ -70,7 +88,7 @@ namespace stream {
|
|
|
template <typename F>
|
|
|
auto flatmap(F && fun) const
|
|
|
-> either_stream<traits::either_value_t<result_of<F>>, E> {
|
|
|
- if (value_.index() == 0) {
|
|
|
+ if (*this) {
|
|
|
return fun(std::get<0>(value_));
|
|
|
} else {
|
|
|
return std::get<1>(value_);
|
|
|
@@ -80,7 +98,7 @@ namespace stream {
|
|
|
template <typename FT, typename FE>
|
|
|
auto match(FT && left, FE && right)
|
|
|
-> std::common_type_t<result_of<FT, T>, result_of<FE, E>> {
|
|
|
- if (value_.index() == 0) {
|
|
|
+ if (*this) {
|
|
|
return left(std::get<0>(value_));
|
|
|
} else {
|
|
|
return right(std::get<1>(value_));
|