cutelyst 5.0.0
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
CoroContext.h
1/*
2 * SPDX-FileCopyrightText: (C) 2024-2025 Daniel Nicoletti <dantti12@gmail.com>
3 * SPDX-FileCopyrightText: (C) 2025 Matthias Fehring <mf@huessenbergnetz.de>
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6#pragma once
7
8#include <Cutelyst/async.h>
9#include <Cutelyst/controller.h>
10#include <coroutine>
11#include <functional>
12#include <memory>
13
14#include <QObject>
15
16namespace Cutelyst {
17
36{
37public:
38 struct promise_type {
39 std::coroutine_handle<promise_type> handle;
40 std::vector<QMetaObject::Connection> connections;
41
42 void clean()
43 {
44 for (auto &conn : connections) {
46 }
47 connections.clear();
48 }
49
50 void return_void() noexcept {}
51
52 CoroContext get_return_object()
53 {
54 handle = std::coroutine_handle<promise_type>::from_promise(*this);
55 return {};
56 }
57
58 std::suspend_never initial_suspend() const noexcept { return {}; }
59 std::suspend_never final_suspend() noexcept { return {}; }
60 void unhandled_exception() {}
61
62 bool await_ready() const noexcept { return false; }
63 void await_suspend(std::coroutine_handle<> h) noexcept {}
64 void await_resume() const noexcept
65 {
66 Q_ASSERT_X(!connections.empty(), "Cutelyst::CoroContext", "Did not yield any QObject*");
67 }
68
69 std::suspend_never yield_value(QObject *obj)
70 {
71 auto conn = QObject::connect(obj, &QObject::destroyed, [this] {
72 clean();
73
74 if (handle) {
75 handle.destroy();
76 }
77 });
78 connections.emplace_back(std::move(conn));
79 return {};
80 }
81
82 std::suspend_never yield_value(Cutelyst::Context *context)
83 {
84 trackContext(context);
85 return {};
86 }
87
88 promise_type() = default; // required for lambdas
89
90 template <typename... ArgTypes>
91 promise_type(QObject &obj, Cutelyst::Context *context, ArgTypes &&...)
92 {
93 Q_UNUSED(obj);
94 trackContext(context);
95 }
96
97 void trackContext(Context *context)
98 {
99 // Automatically delay replies
100 // async cannot be used in coroutine body
101 // else we get a double free when the coroutine
102 // body ends and Cutelyst::Engine deletes the Context*
103 // resulting in destroyed signal being emitted and
104 // and coroutine dtor already on the stack to be called
105 ASync a(context);
106
107 auto conn = QObject::connect(context, &QObject::destroyed, [this, a] {
108 clean();
109
110 if (handle) {
111 handle.destroy();
112 }
113 });
114 connections.emplace_back(std::move(conn));
115 }
116
117 ~promise_type() { clean(); }
118 };
119};
120
121} // namespace Cutelyst
Helper class for asynchronous processing.
Definition async.h:16
The Cutelyst Context.
Definition context.h:42
The CoroContext class.
Definition CoroContext.h:36
The Cutelyst namespace holds all public Cutelyst API.
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void destroyed(QObject *obj)
bool disconnect(const QMetaObject::Connection &connection)