mirror of
https://github.com/Naios/continuable.git
synced 2025-12-06 08:46:44 +08:00
143 lines
5.6 KiB
Plaintext
143 lines
5.6 KiB
Plaintext
/*
|
|
Copyright(c) 2015 - 2019 Denis Blank <denis.blank at outlook dot com>
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files(the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions :
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
*/
|
|
|
|
namespace cti {
|
|
/** \page tutorial-creating-continuables Creating continuables
|
|
\brief Explains how to create a \ref continuable_base.
|
|
|
|
\tableofcontents
|
|
|
|
A \ref continuable is an arbitrary instantiation of a \ref continuable_base,
|
|
it represents the main class of the library and makes it possible to build up
|
|
an asynchronous call hierarchy. When dealing with continuables we usually don't
|
|
know its exact type for avoiding expensive type erasure.
|
|
|
|
The \ref continuable_base is convertible to a \ref continuable which represents
|
|
a specified type of the \ref continuable_base on the cost of a type erasure.
|
|
|
|
\section tutorial-creating-continuables-ready From a value or exception
|
|
|
|
The library provides \ref make_ready_continuable which may be used to create a
|
|
\ref continuable_base from an arbitrary amount of values:
|
|
|
|
\code{.cpp}
|
|
auto one = cti::make_ready_continuable(0);
|
|
|
|
cti::continuable<int, float, char> three =
|
|
cti::make_ready_continuable(0, 1.f, '2');
|
|
\endcode
|
|
|
|
\note In most situations you will never use \ref make_ready_continuable
|
|
because the library is capable of working with plain values
|
|
directly and thus this burdens unnecessary overhead.
|
|
|
|
Additionally a \ref continuable_base which resolves with an exception may be
|
|
created through \ref make_exceptional_continuable.
|
|
|
|
\code{.cpp}
|
|
cti::continuable<int> c = cti::make_exceptional_continuable(std::exception{});
|
|
\endcode
|
|
|
|
\section tutorial-creating-continuables-promises From a promise taking callable
|
|
|
|
The main function for creating a \ref continuable_base is \ref make_continuable
|
|
which must be invoked with the types of arguments it resolves to.
|
|
It accepts a callable object which accepts an arbitrary object
|
|
(the \ref promise_base). The \ref promise_base is created by the library and
|
|
then passed to the given callback. This is in contrast to the usage of the
|
|
standard `std::promise` which is created by the user.
|
|
|
|
The \ref promise_base exposes methods to resolve it through result values or
|
|
through an exception. Below we implement pseudo `http_request` function
|
|
which resolves the request asynchronously trough a `std::string`.
|
|
|
|
\code{.cpp}
|
|
auto http_request(std::string url) {
|
|
return cti::make_continuable<std::string>(
|
|
[url = std::move(url)](auto&& promise) {
|
|
// Resolve the promise upon completion of the task.
|
|
promise.set_value("<html> ... </html>");
|
|
|
|
// Or promise.set_exception(...);
|
|
});
|
|
}
|
|
\endcode
|
|
|
|
An alternative would be a \ref continuable_base with a result of zero arguments:
|
|
|
|
\code{.cpp}
|
|
auto wait_for(std::chrono::milliseconds duration) {
|
|
return cti::make_continuable<void>([](auto&& promise) {
|
|
// ^^^^
|
|
|
|
// Resolve the promise later when the duration is over
|
|
promise.set_value();
|
|
});
|
|
\endcode
|
|
|
|
A \ref continuable_base may resolve with an arbitrary count of result values:
|
|
|
|
\code{.cpp}
|
|
auto resolve_sth() {
|
|
return cti::make_continuable<int, int, float, char>(
|
|
[](auto&& promise) {
|
|
promise.set_value(0, 1, 2.f, '3');
|
|
});
|
|
\endcode
|
|
|
|
\warning A \ref promise_base is only usable once and thus invalidated
|
|
after it was resolved!
|
|
|
|
A \ref promise_base always exposes a call operator for resolving it as
|
|
like when using \ref promise_base::set_value or
|
|
\ref promise_base::set_exception. See \ref promise_base for details.
|
|
|
|
\note In order to make proper use of a \ref promise_base you should
|
|
move it around, store it for later use and resolve it when
|
|
the asynchronous task was finished or rejected.
|
|
|
|
\section tutorial-creating-continuables-invocation The continuable invocation model
|
|
|
|
An asynchronous call hierarchy that is stored inside the \ref continuable_base
|
|
is executed when its result is requested (lazy evaluation) in contrast to
|
|
other commonly used implementations such as `std::future` which execute the
|
|
asynchronous call hierarchy instantly on creation (eager evaluation).
|
|
|
|
The lazy evaluation strategy used by continuables has many benefits over
|
|
eager evaluation that is used by other common implementations:
|
|
- prevention of side effects
|
|
- evasion of race conditions
|
|
- ensured deterministic behaviour.
|
|
|
|
The asynchronous call hierarchy is started when the \ref continuable_base is
|
|
destructed or the \ref continuable_base::done method is called.
|
|
It is possible to disable the automatic start through calling
|
|
\ref continuable_base::freeze on the corresponding \ref continuable_base.
|
|
|
|
\attention A \ref continuable_base is not designed to be stored permanently,
|
|
make sure you call \ref continuable_base::freeze before storing it
|
|
and start the continuation chain later through calling
|
|
\ref continuable_base::done.
|
|
|
|
*/
|
|
}
|