LeechCraft 0.6.70-19214-g121e5318a7
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
signal.h
Go to the documentation of this file.
1/**********************************************************************
2 * LeechCraft - modular cross-platform feature rich internet client.
3 * Copyright (C) 2006-2014 Georg Rudoy
4 *
5 * Distributed under the Boost Software License, Version 1.0.
6 * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7 **********************************************************************/
8
9#pragma once
10
11#include <concepts>
12#include <coroutine>
13#include <exception>
14#include <functional>
15#include <optional>
16#include <tuple>
17#include <type_traits>
18#include <utility>
19#include <QObject>
20#include <util/sll/typelist.h>
21#include <util/sll/void.h>
22
23namespace LC::Util::detail
24{
25 template<typename T>
26 concept PrivateSignalTag = std::same_as<T, class T::QPrivateSignal>;
27
28 template<typename... Args>
30 {
31 using Ret = std::tuple<std::decay_t<Args>...>;
32 using Arg = Void;
33
35
36 Ret Collect (Args... args) const
37 {
38 return Ret { args... };
39 }
40
41 static auto GetRet (std::optional<Ret>&& result)
42 {
43 constexpr auto ArgsCount = sizeof... (Args);
44
45 if constexpr (ArgsCount == 1)
46 return std::move (result)
47 .transform ([] (Ret&& tup) { return std::get<0> (std::move (tup)); });
48 else if constexpr (ArgsCount > 1)
49 return std::move (result);
50 else
51 return static_cast<bool> (result);
52 }
53 };
54
55 template<typename FunType>
57 {
58 template<typename... Args>
59 struct Handler
60 {
61 using Ret = std::invoke_result_t<FunType, Args...>;
62 using Arg = FunType;
63
65
66 Ret Collect (Args... args)
67 {
68 return std::invoke (Fun_, std::move (args)...);
69 }
70
71 static auto GetRet (std::optional<Ret>&& result)
72 {
73 return std::move (result);
74 }
75 };
76 };
77
78 template<
79 std::derived_from<QObject> Obj,
80 template<typename...> typename SyncHandler,
81 typename Sig,
82 typename... SlotArgs
83 >
85 {
86 struct RetHolder : QObject
87 {
88 using Handler = SyncHandler<SlotArgs...>;
90
91 std::optional<typename Handler::Ret> Result_ {};
92 std::coroutine_handle<> Cont_ {};
93 std::exception_ptr Exception_ {};
94
95 explicit(false) RetHolder (Handler::Arg arg)
96 : Handler_ { arg }
97 {
98 }
99
100 void Handle (SlotArgs... args)
101 {
102 try
103 {
104 Result_.emplace (Handler_.Collect (std::move (args)...));
105 }
106 catch (...)
107 {
108 Exception_ = std::current_exception ();
109 }
110
111 QMetaObject::invokeMethod (this, Cont_, Qt::QueuedConnection);
112 }
113
115 {
116 if (!Result_ && !Exception_)
117 QMetaObject::invokeMethod (this, Cont_, Qt::QueuedConnection);
118 }
119
120 auto GetRet ()
121 {
122 if (Exception_)
123 std::rethrow_exception (Exception_);
124 return Handler::GetRet (std::move (Result_));
125 }
126 };
127
128 Obj& Obj_;
129 Sig Sig_;
131
132 bool await_ready () const noexcept
133 {
134 return false;
135 }
136
137 void await_suspend (std::coroutine_handle<> handle) noexcept
138 {
139 Holder_.Cont_ = handle;
140 QObject::connect (&Obj_,
141 Sig_,
142 &Holder_,
144 Qt::SingleShotConnection);
145 QObject::connect (&Obj_,
146 &QObject::destroyed,
147 &Holder_,
149 }
150
152 {
153 return Holder_.GetRet ();
154 }
155 };
156
157 template<
158 std::derived_from<QObject> Obj,
159 template<typename...> typename SyncHandler,
160 typename Sig,
161 typename... SlotArgs
162 >
164 {
165 Obj& Obj_;
166 Sig Sig_;
167
168 SyncHandler<SlotArgs...>::Arg SyncHandlerArg_ {};
169
170 SignalAwaiter<Obj, SyncHandler, Sig, SlotArgs...> operator co_await () const
171 {
172 return { Obj_, Sig_, { SyncHandlerArg_ } };
173 }
174 };
175}
176
177namespace LC::Util
178{
179 template<std::derived_from<QObject> Obj, template<typename...> typename SyncHandler, typename Sig, typename SlotArgsList>
180 struct Signal {};
181
182 template<std::derived_from<QObject> Obj, template<typename...> typename SyncHandler, typename Sig, typename... SlotArgs>
183 struct Signal<Obj, SyncHandler, Sig, Typelist<SlotArgs...>> : detail::SignalBase<Obj, SyncHandler, Sig, SlotArgs...> {};
184
185 template<std::derived_from<QObject> Obj, template<typename...> typename SyncHandler, typename Sig, typename... SlotArgs>
186 requires (sizeof... (SlotArgs) > 0) && detail::PrivateSignalTag<SlotArgs... [sizeof... (SlotArgs) - 1]>
187 struct Signal<Obj, SyncHandler, Sig, Typelist<SlotArgs...>> : Signal<Obj, SyncHandler, Sig, decltype (Init (Typelist<SlotArgs...> {}))> {};
188
189 template<
190 std::derived_from<QObject> Base,
191 std::derived_from<Base> Derived,
192 typename... SignalArgs
193 >
194 Signal (Derived&, void (Base::*) (SignalArgs...))
195 -> Signal<
196 Base,
198 void (Base::*) (SignalArgs...),
199 Typelist<SignalArgs...>
200 >;
201
202 template<
203 std::derived_from<QObject> Base,
204 std::derived_from<Base> Derived,
205 typename Handler,
206 typename... SignalArgs
207 >
208 Signal (Derived&, void (Base::*) (SignalArgs...), Handler)
209 -> Signal<
210 Base,
212 void (Base::*) (SignalArgs...),
213 Typelist<SignalArgs...>
214 >;
215}
A proper void type, akin to unit (or ()) type in functional languages.
Definition void.h:21
static auto GetRet(std::optional< Ret > &&result)
Definition signal.h:71
std::invoke_result_t< FunType, Args... > Ret
Definition signal.h:61
std::optional< typename Handler::Ret > Result_
Definition signal.h:91
SyncHandler< SlotArgs... > Handler
Definition signal.h:88
bool await_ready() const noexcept
Definition signal.h:132
void await_suspend(std::coroutine_handle<> handle) noexcept
Definition signal.h:137
SyncHandler< SlotArgs... >::Arg SyncHandlerArg_
Definition signal.h:168
std::tuple< std::decay_t< Args >... > Ret
Definition signal.h:31
static auto GetRet(std::optional< Ret > &&result)
Definition signal.h:41
Ret Collect(Args... args) const
Definition signal.h:36