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 }