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 "future.h" 0008 0009 #if defined(__clang__) 0010 0011 #include <experimental/coroutine> 0012 namespace coroutine_namespace = std::experimental; 0013 0014 #elif defined(__GNUC__) 0015 0016 #include <coroutine> 0017 namespace coroutine_namespace = std; 0018 0019 #endif 0020 0021 namespace Croutons 0022 { 0023 0024 // responsible for providing the overload of await_transform 0025 template<typename T> 0026 struct transformer { 0027 static T transform(const T& t) { 0028 return t; 0029 } 0030 }; 0031 0032 }; // namespace Croutons 0033 0034 template<typename... Args> 0035 struct coroutine_namespace::coroutine_traits<Croutons::FutureBase, Args...> { 0036 struct promise_type { 0037 private: 0038 Croutons::FutureBase t; 0039 0040 public: 0041 Croutons::FutureBase get_return_object() noexcept { 0042 return t; 0043 } 0044 0045 coroutine_namespace::suspend_never initial_suspend() const noexcept { return {}; } 0046 coroutine_namespace::suspend_never final_suspend() const noexcept { return {}; } 0047 0048 void return_value(const QVariant& value) noexcept { 0049 t.succeed(value); 0050 } 0051 void return_value(QVariant&& value) noexcept { 0052 t.succeed(std::move(value)); 0053 } 0054 0055 template<typename Awaited> 0056 auto await_transform(const Awaited& t) { 0057 return Croutons::transformer<Awaited>::transform(t); 0058 } 0059 0060 void unhandled_exception() noexcept { 0061 Q_ASSERT("unhandled exception"); 0062 } 0063 }; 0064 }; 0065 0066 inline auto operator co_await(Croutons::FutureBase it) noexcept { 0067 struct Awaiter { 0068 Croutons::FutureBase future; 0069 0070 bool await_ready() const noexcept { 0071 return future.settled(); 0072 } 0073 void await_suspend(coroutine_namespace::coroutine_handle<> cont) const { 0074 future.then([cont](QVariant) mutable { cont(); }, [cont](QVariant) mutable { cont(); }); 0075 } 0076 QVariant await_resume() { 0077 return future.result(); 0078 } 0079 }; 0080 0081 return Awaiter{it}; 0082 } 0083 0084 template<typename T, typename... Args> 0085 struct coroutine_namespace::coroutine_traits<Croutons::Future<T>, Args...> { 0086 struct promise_type { 0087 private: 0088 Croutons::Future<T> v; 0089 0090 public: 0091 Croutons::Future<T> get_return_object() noexcept { 0092 return v; 0093 } 0094 0095 coroutine_namespace::suspend_never initial_suspend() const noexcept { return {}; } 0096 coroutine_namespace::suspend_never final_suspend() const noexcept { return {}; } 0097 0098 void return_value(const T& value) noexcept { 0099 v.succeed(value); 0100 } 0101 void return_value(T&& value) noexcept { 0102 v.succeed(std::move(value)); 0103 } 0104 0105 template<typename Awaited> 0106 auto await_transform(const Awaited& t) { 0107 return Croutons::transformer<Awaited>::transform(t); 0108 } 0109 0110 void unhandled_exception() noexcept { 0111 Q_ASSERT("unhandled exception"); 0112 } 0113 }; 0114 }; 0115 0116 template<typename... Args> 0117 struct coroutine_namespace::coroutine_traits<Croutons::Future<void>, Args...> { 0118 struct promise_type { 0119 private: 0120 Croutons::Future<void> v; 0121 0122 public: 0123 Croutons::Future<void> get_return_object() noexcept { 0124 return v; 0125 } 0126 0127 coroutine_namespace::suspend_never initial_suspend() const noexcept { return {}; } 0128 coroutine_namespace::suspend_never final_suspend() const noexcept { return {}; } 0129 0130 void return_void() noexcept { 0131 v.succeed(); 0132 } 0133 0134 template<typename Awaited> 0135 auto await_transform(const Awaited& t) { 0136 return Croutons::transformer<Awaited>::transform(t); 0137 } 0138 0139 void unhandled_exception() noexcept { 0140 Q_ASSERT("unhandled exception"); 0141 } 0142 }; 0143 }; 0144 0145 template<typename T> 0146 auto operator co_await(Croutons::Future<T> it) noexcept { 0147 struct Awaiter { 0148 Croutons::Future<T> future; 0149 0150 bool await_ready() const noexcept { 0151 return future.settled(); 0152 } 0153 void await_suspend(coroutine_namespace::coroutine_handle<> cont) const { 0154 future.then([cont](T) mutable { cont(); }, [cont](T) mutable { cont(); }); 0155 } 0156 T await_resume() { 0157 return future.result(); 0158 } 0159 }; 0160 0161 return Awaiter{it}; 0162 } 0163 0164 template<> 0165 inline auto operator co_await(Croutons::Future<void> it) noexcept { 0166 struct Awaiter { 0167 Croutons::Future<void> future; 0168 0169 bool await_ready() const noexcept { 0170 return future.settled(); 0171 } 0172 void await_suspend(coroutine_namespace::coroutine_handle<> cont) const { 0173 future.then([cont]() mutable { cont(); }, [cont]() mutable { cont(); }); 0174 } 0175 void await_resume() { 0176 return; 0177 } 0178 }; 0179 0180 return Awaiter{it}; 0181 } 0182 0183 template<typename T, typename Error, typename... Args> 0184 struct coroutine_namespace::coroutine_traits<Croutons::FutureResult<T, Error>, Args...> { 0185 struct promise_type { 0186 private: 0187 Croutons::FutureResult<T, Error> v; 0188 0189 public: 0190 Croutons::FutureResult<T, Error> get_return_object() noexcept { 0191 return v; 0192 } 0193 0194 coroutine_namespace::suspend_never initial_suspend() const noexcept { return {}; } 0195 coroutine_namespace::suspend_never final_suspend() const noexcept { return {}; } 0196 0197 void return_value(const Croutons::Result<T, Error>& value) noexcept { 0198 v.finish(value); 0199 } 0200 void return_value(const T& value) noexcept { 0201 v.succeed(value); 0202 } 0203 void return_value(const Error& value) noexcept { 0204 v.fail(value); 0205 } 0206 void return_value(Croutons::Result<T, Error>&& value) noexcept { 0207 v.finish(std::move(value)); 0208 } 0209 0210 template<typename Awaited> 0211 auto await_transform(const Awaited& t) { 0212 return Croutons::transformer<Awaited>::transform(t); 0213 } 0214 0215 void unhandled_exception() noexcept { 0216 Q_ASSERT("unhandled exception"); 0217 } 0218 }; 0219 }; 0220 0221 template<typename T, typename Error> 0222 auto operator co_await(Croutons::FutureResult<T, Error> it) noexcept { 0223 struct Awaiter { 0224 Croutons::FutureResult<T, Error> future; 0225 0226 bool await_ready() const noexcept { 0227 return future.settled(); 0228 } 0229 void await_suspend(coroutine_namespace::coroutine_handle<> cont) const { 0230 future.then([cont](Croutons::Result<T ,Error>) mutable { cont(); }); 0231 } 0232 Croutons::Result<T, Error> await_resume() { 0233 return Croutons::Result<T, Error>{future.result()}; 0234 } 0235 }; 0236 0237 return Awaiter{it}; 0238 }