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 "coroutine_integration.h"
0008 
0009 #include <functional>
0010 #include <type_traits>
0011 
0012 #define perform co_await
0013 
0014 template<typename T>
0015 class Effect {
0016     struct Holder {
0017         T t;
0018     };
0019     QSharedPointer<Holder> val;
0020 
0021 public:
0022     Effect() {
0023         val.reset(new Holder);
0024     }
0025     Effect(const Effect& other) {
0026         val = other.val;
0027     }
0028     operator T() const {
0029         return val->t;
0030     }
0031 
0032     struct promise_type {
0033     private:
0034         Effect<T> t;
0035 
0036     public:
0037         promise_type() {
0038             t = Effect<T>{};
0039         }
0040 
0041         Effect<T> 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 T& value) noexcept {
0049             t.val->t = value;
0050         }
0051         void return_value(T&& value) noexcept {
0052             t.val->t = std::move(value);
0053         }
0054 
0055         void unhandled_exception() noexcept {
0056             Q_ASSERT("unhandled exception");
0057         }
0058     };
0059 };
0060 
0061 template<>
0062 class Effect<void> {
0063 };
0064 
0065 template<typename ...Args>
0066 struct coroutine_namespace::coroutine_traits<Effect<void>, Args...>
0067 {
0068     struct promise_type {
0069     private:
0070         Effect<void> t;
0071 
0072     public:
0073         promise_type() {
0074             t = Effect<void>{};
0075         }
0076 
0077         Effect<void> get_return_object() noexcept {
0078             return t;
0079         }
0080 
0081         coroutine_namespace::suspend_never initial_suspend() const noexcept { return {}; }
0082         coroutine_namespace::suspend_never final_suspend() const noexcept { return {}; }
0083 
0084         void return_void() noexcept {
0085         }
0086 
0087         void unhandled_exception() noexcept {
0088             Q_ASSERT("unhandled exception");
0089         }
0090     };
0091 };
0092 
0093 template<typename Fn>
0094 class EffectVoidFun {
0095     static thread_local QList<Fn> items;
0096 
0097 public:
0098 
0099     template<typename... Args>
0100     EffectVoidFun(Args&&... args) {
0101         items.last()(std::forward<Args>(args)...);
0102     }
0103 
0104     static auto handler(Fn fn) {
0105         items << fn;
0106         struct Deleter {
0107             ~Deleter() {
0108                 items.pop_back();
0109             }
0110         };
0111         return Deleter{};
0112     }
0113 
0114     bool await_ready() const noexcept {
0115         return true;
0116     }
0117     void await_suspend(coroutine_namespace::coroutine_handle<> cont) const {
0118         cont();
0119     }
0120     void await_resume() {
0121         return;
0122     }
0123 };
0124 
0125 template<typename T>
0126 inline thread_local QList<T> EffectVoidFun<T>::items;
0127 
0128 template<typename Fn>
0129 class EffectFun {
0130     static thread_local QList<Fn> items;
0131     typename Fn::result_type ret;
0132 
0133 public:
0134 
0135     template<typename... Args>
0136     EffectFun(Args&&... args) {
0137         ret = items.last()(std::forward<Args>(args)...);
0138     }
0139 
0140     static auto handler(Fn fn) {
0141         items << fn;
0142         struct Deleter {
0143             ~Deleter() {
0144                 items.pop_back();
0145             }
0146         };
0147         return Deleter{};
0148     }
0149 
0150     bool await_ready() const noexcept {
0151         return true;
0152     }
0153     void await_suspend(coroutine_namespace::coroutine_handle<> cont) const {
0154         cont();
0155     }
0156     typename Fn::result_type await_resume() {
0157         return ret;
0158     }
0159 };
0160 
0161 template<typename T>
0162 inline thread_local QList<T> EffectFun<T>::items;