File indexing completed on 2024-05-05 04:41:15
0001 // SPDX-FileCopyrightText: 2021 Carson Black <uhhadd@gmail.com> 0002 // 0003 // SPDX-License-Identifier: MIT 0004 0005 #pragma once 0006 0007 #include "futurebase.h" 0008 0009 namespace Croutons 0010 { 0011 0012 template<typename T> 0013 concept Variantable = requires(T a) { 0014 QVariant::fromValue(a); 0015 }; 0016 0017 template<typename T, typename Error> 0018 requires (!std::is_same_v<T, Error>) 0019 struct Result { 0020 std::variant<T, Error> it; 0021 0022 T value() const { 0023 return std::get<T>(it); 0024 } 0025 Error error() const { 0026 return std::get<Error>(it); 0027 } 0028 0029 bool ok() const { 0030 return std::holds_alternative<T>(it); 0031 } 0032 }; 0033 0034 template<typename T = void> 0035 requires (Variantable<T> || std::is_same_v<T, void>) class Future : public FutureBase 0036 { 0037 0038 public: 0039 using Kind = T; 0040 0041 Future() : FutureBase() { 0042 } 0043 Future(const FutureBase& other) : FutureBase(other) { 0044 } 0045 void succeed(const T& it) const { 0046 FutureBase::succeed(QVariant::fromValue(it)); 0047 } 0048 void fail(const T& it) const { 0049 FutureBase::succeed(QVariant::fromValue(it)); 0050 } 0051 T result() const { 0052 Q_ASSERT(settled()); 0053 0054 return FutureBase::result().template value<T>(); 0055 } 0056 void then(std::function<void(T)> callback, std::function<void(T)> orElse = [](T){}) const { 0057 auto wrap1 = [callback](QVariant r) { callback(qvariant_cast<T>(r)); }; 0058 auto wrap2 = [orElse](QVariant r) { orElse(qvariant_cast<T>(r)); }; 0059 FutureBase::then(wrap1, wrap2); 0060 } 0061 template<typename Function> 0062 Future<typename std::invoke_result_t<Function, T>::Kind> 0063 flatMap(Function callback) const { 0064 using NewT = typename std::invoke_result_t<Function, T>::Kind; 0065 0066 Future<NewT> ret; 0067 0068 auto wrap1 = [callback, ret](QVariant r) { 0069 auto bret = callback(qvariant_cast<T>(r)); 0070 0071 bret.then([ret](NewT t) { ret.succeed(t); }, [ret](NewT t) { ret.fail(t); }); 0072 }; 0073 0074 FutureBase::then(wrap1); 0075 0076 return ret; 0077 } 0078 template<typename Function> 0079 Future<typename std::invoke_result_t<Function, T>> 0080 map(Function callback) const { 0081 using NewT = std::invoke_result_t<Function, T>; 0082 Future<NewT> ret; 0083 0084 auto wrap1 = [callback, ret](QVariant r) { 0085 ret.succeed(callback(qvariant_cast<T>(r))); 0086 }; 0087 0088 FutureBase::then(wrap1); 0089 0090 return ret; 0091 } 0092 }; 0093 0094 template<> 0095 class Future<void> : public FutureBase 0096 { 0097 0098 public: 0099 void succeed() const { 0100 FutureBase::succeed(QVariant()); 0101 } 0102 void fail() const { 0103 FutureBase::succeed(QVariant()); 0104 } 0105 void then(std::function<void()> callback, std::function<void()> orElse = [](){}) const { 0106 auto wrap1 = [callback](QVariant) { callback(); }; 0107 auto wrap2 = [orElse](QVariant) { orElse(); }; 0108 FutureBase::then(wrap1, wrap2); 0109 } 0110 }; 0111 0112 struct Error { 0113 QString err; 0114 }; 0115 0116 struct Nil {}; 0117 0118 template<typename T = Nil, typename Error = Error> 0119 requires Variantable<T>&& Variantable<Error> && (!std::is_same_v<T, Error>) class FutureResult : public FutureBase 0120 { 0121 0122 public: 0123 FutureResult() : FutureBase() { 0124 } 0125 FutureResult(const FutureBase& other) : FutureBase(other) { 0126 } 0127 void succeed(const T& it) const { 0128 FutureBase::succeed(QVariant::fromValue(it)); 0129 } 0130 void fail(const Error& it) const { 0131 FutureBase::fail(QVariant::fromValue(it)); 0132 } 0133 void finish(const Result<T, Error>& it) const { 0134 if (it.ok()) { 0135 succeed(it.value()); 0136 } else { 0137 fail(it.error()); 0138 } 0139 } 0140 0141 Result<T, Error> result() const { 0142 Q_ASSERT(settled()); 0143 0144 Result<T, Error> res; 0145 0146 if (!success()) { 0147 res = Result<T, Error> { .it = FutureBase::result().template value<Error>() }; 0148 } else { 0149 res = Result<T, Error> { .it = FutureBase::result().template value<T>() }; 0150 } 0151 0152 return res; 0153 } 0154 void then(std::function<void(Result<T, Error>)> callback) const { 0155 auto wrap = [callback, *this](QVariant) { callback(this->result()); }; 0156 FutureBase::then(wrap, wrap); 0157 } 0158 Future<T> toFutureT() { 0159 Future<T> ret; 0160 0161 then([ret](Result<T, Error> res) mutable { 0162 if (res.ok()) { 0163 ret.succeed(res.value()); 0164 } 0165 }); 0166 0167 return ret; 0168 } 0169 }; 0170 0171 } // namespace Croutons 0172 0173 Q_DECLARE_METATYPE(Croutons::Error) 0174 Q_DECLARE_METATYPE(Croutons::Nil)