Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F112797
qt-promise-handler.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
qt-promise-handler.hpp
View Options
/*
* This file is part of kazv.
* SPDX-FileCopyrightText: 2020-2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#pragma once
#include
<libkazv-config.hpp>
#include
<future>
#include
<QObject>
#include
<QMetaObject>
#include
<QPointer>
#include
<QTimer>
#include
<promise-interface.hpp>
template
<
class
T
>
class
QtPromise
;
namespace
QtPromiseDetail
{
struct
QtPromiseHelper
{
template
<
class
T
>
using
PromiseType
=
QtPromise
<
T
>
;
};
struct
IdentityFunc
{
template
<
class
T
>
constexpr
T
&&
operator
()(
T
&&
t
)
const
{
return
std
::
forward
<
T
>
(
t
);
}
};
template
<
class
Func
>
void
post
(
QObject
*
obj
,
Func
&&
func
)
{
QMetaObject
::
invokeMethod
(
obj
,
std
::
forward
<
Func
>
(
func
),
Qt
::
QueuedConnection
);
}
}
class
QtPromiseSignalTrigger
:
public
QObject
{
Q_OBJECT
public
:
QtPromiseSignalTrigger
(
QObject
*
parent
=
0
);
~
QtPromiseSignalTrigger
();
Q_SIGNALS
:
void
finished
();
};
template
<
class
T
>
class
QtPromise
:
public
Kazv
::
AbstractPromise
<
QtPromiseDetail
::
QtPromiseHelper
::
PromiseType
,
T
>
{
using
BaseT
=
Kazv
::
AbstractPromise
<
QtPromiseDetail
::
QtPromiseHelper
::
PromiseType
,
T
>
;
template
<
class
FuncT
,
class
PromiseT
,
class
ResolveT
>
struct
WaitHelper
{
void
resolveOrWait
()
{
auto
res
=
func
(
p
.
get
());
using
ResT
=
decltype
(
res
);
if
constexpr
(
Kazv
::
isPromise
<
ResT
>
)
{
res
.
then
([
resolve
=
resolve
](
auto
val
)
{
resolve
(
std
::
move
(
val
));
return
std
::
decay_t
<
decltype
(
val
)
>
();
// we don't care about this value
});
}
else
{
resolve
(
res
);
}
}
void
wait
()
{
if
(
p
.
ready
())
{
QtPromiseDetail
::
post
(
executor
,
[
*
this
]()
mutable
{
resolveOrWait
();
}
);
}
else
{
QObject
::
connect
(
p
.
m_signalTrigger
,
&
QtPromiseSignalTrigger
::
finished
,
executor
,
[
*
this
]()
mutable
{
resolveOrWait
();
}
);
}
}
QPointer
<
QObject
>
executor
;
PromiseT
p
;
FuncT
func
;
ResolveT
resolve
;
};
struct
ResolveHelper
{
template
<
class
ValT
>
void
operator
()(
ValT
val
)
const
{
using
ResT
=
std
::
decay_t
<
decltype
(
val
)
>
;
if
constexpr
(
Kazv
::
isPromise
<
ResT
>
)
{
QtPromiseDetail
::
post
(
executor
,
[
qtPromise
=
std
::
move
(
val
),
*
this
]()
mutable
{
if
(
qtPromise
.
ready
())
{
setValue
(
qtPromise
.
get
());
}
else
{
qtPromise
.
then
([
*
this
](
auto
val
)
mutable
{
setValue
(
std
::
move
(
val
));
return
std
::
decay_t
<
decltype
(
val
)
>
();
// we don't care about this value
});
}
});
}
else
{
QtPromiseDetail
::
post
(
executor
,
[
*
this
,
val
=
std
::
move
(
val
)]()
mutable
{
setValue
(
std
::
move
(
val
));
});
}
}
void
setValue
(
T
resolvedValue
)
const
{
p
->
set_value
(
std
::
move
(
resolvedValue
));
if
(
signalTrigger
)
{
Q_EMIT
signalTrigger
->
finished
();
signalTrigger
->
deleteLater
();
}
}
QPointer
<
QObject
>
executor
;
QPointer
<
QtPromiseSignalTrigger
>
signalTrigger
;
std
::
shared_ptr
<
std
::
promise
<
T
>>
p
;
};
public
:
QtPromise
(
QObject
*
executor
,
T
value
)
:
BaseT
(
this
)
,
m_executor
(
executor
)
,
m_signalTrigger
()
{
std
::
promise
<
T
>
p
;
m_val
=
p
.
get_future
().
share
();
p
.
set_value
(
std
::
move
(
value
));
}
template
<
class
Func
>
QtPromise
(
QObject
*
executor
,
Func
&&
callback
)
:
BaseT
(
this
)
,
m_executor
(
executor
)
,
m_signalTrigger
(
new
QtPromiseSignalTrigger
())
{
auto
p
=
std
::
make_shared
<
std
::
promise
<
T
>>
();
m_val
=
p
->
get_future
().
share
();
m_signalTrigger
->
moveToThread
(
m_executor
->
thread
());
auto
resolve
=
ResolveHelper
{
m_executor
,
m_signalTrigger
,
p
};
QtPromiseDetail
::
post
(
m_executor
,
[
=
,
callback
=
std
::
forward
<
Func
>
(
callback
),
resolve
=
std
::
move
(
resolve
)]()
{
callback
(
resolve
);
});
}
// FuncT: (DataT) -> AnotherDataT
// where AnotherDataT = PromiseThenResult<FuncT, typename BaseT::DataT>
template
<
class
FuncT
>
auto
then
(
FuncT
&&
func
)
->
QtPromise
<
Kazv
::
PromiseThenResult
<
FuncT
,
typename
BaseT
::
DataT
>>
{
return
QtPromise
<
Kazv
::
PromiseThenResult
<
FuncT
,
typename
BaseT
::
DataT
>>
(
m_executor
,
[
=
,
func
=
std
::
forward
<
FuncT
>
(
func
),
*
this
](
auto
resolve
)
{
auto
waitHelper
=
WaitHelper
<
std
::
decay_t
<
FuncT
>
,
QtPromise
,
std
::
decay_t
<
decltype
(
resolve
)
>>
{
m_executor
,
*
this
,
func
,
resolve
};
waitHelper
.
wait
();
});
}
bool
ready
()
const
{
return
m_val
.
wait_for
(
std
::
chrono
::
seconds
(
0
))
==
std
::
future_status
::
ready
;
}
T
get
()
const
{
return
m_val
.
get
();
}
private
:
QPointer
<
QObject
>
m_executor
;
QPointer
<
QtPromiseSignalTrigger
>
m_signalTrigger
;
std
::
shared_future
<
T
>
m_val
;
};
class
QtPromiseHandler
:
public
Kazv
::
PromiseInterface
<
QtPromiseHandler
,
QtPromiseDetail
::
QtPromiseHelper
::
PromiseType
>
{
using
BaseT
=
Kazv
::
PromiseInterface
<
QtPromiseHandler
,
QtPromiseDetail
::
QtPromiseHelper
::
PromiseType
>
;
public
:
template
<
class
T
>
using
PromiseT
=
QtPromise
<
T
>
;
QtPromiseHandler
(
std
::
reference_wrapper
<
QObject
>
executor
)
:
BaseT
(
this
)
,
m_executor
(
&
executor
.
get
())
{}
QtPromiseHandler
(
const
QtPromiseHandler
&
that
)
:
BaseT
(
this
)
,
m_executor
(
that
.
m_executor
)
{}
QtPromiseHandler
(
QtPromiseHandler
&&
that
)
:
BaseT
(
this
)
,
m_executor
(
std
::
move
(
that
.
m_executor
))
{}
QtPromiseHandler
&
operator
=
(
const
QtPromiseHandler
&
that
)
{
m_executor
=
that
.
m_executor
;
return
*
this
;
}
QtPromiseHandler
&
operator
=
(
QtPromiseHandler
&&
that
)
{
m_executor
=
std
::
move
(
that
.
m_executor
);
return
*
this
;
}
template
<
class
T
,
class
FuncT
>
PromiseT
<
T
>
create
(
FuncT
&&
func
)
{
return
PromiseT
<
T
>
(
m_executor
,
std
::
forward
<
FuncT
>
(
func
));
}
template
<
class
T
>
PromiseT
<
T
>
createResolved
(
T
val
)
{
return
PromiseT
<
T
>
(
m_executor
,
std
::
move
(
val
));
}
private
:
QPointer
<
QObject
>
m_executor
;
};
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sun, Nov 24, 12:07 AM (19 h, 21 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39225
Default Alt Text
qt-promise-handler.hpp (7 KB)
Attached To
Mode
rK kazv
Attached
Detach File
Event Timeline
Log In to Comment