/*
This file is part of TON Blockchain Library.
TON Blockchain Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
TON Blockchain Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with TON Blockchain Library. If not, see .
Copyright 2017-2020 Telegram Systems LLP
*/
#pragma once
#include "td/utils/Closure.h"
#include "td/utils/common.h"
#include "td/utils/invoke.h" // for tuple_for_each
#include "td/utils/logging.h"
#include "td/utils/ScopeGuard.h"
#include "td/utils/Status.h"
#include
#include
#include
namespace td {
namespace detail {
template
struct GetArg : public GetArg {};
template
class GetArg {
public:
using type = Arg;
};
template
class GetArg {
public:
using type = Arg;
};
template
struct GetRet : public GetRet {};
template
class GetRet {
public:
using type = R;
};
template
class GetRet {
public:
using type = R;
};
template
using get_arg_t = std::decay_t::type>;
template
using get_ret_t = std::decay_t::type>;
template
struct DropResult {
using type = T;
};
template
struct DropResult> {
using type = T;
};
template
using drop_result_t = typename DropResult::type;
} // namespace detail
template
class PromiseInterface {
public:
using ValueType = T;
PromiseInterface() = default;
PromiseInterface(const PromiseInterface &) = delete;
PromiseInterface &operator=(const PromiseInterface &) = delete;
PromiseInterface(PromiseInterface &&) = default;
PromiseInterface &operator=(PromiseInterface &&) = default;
virtual ~PromiseInterface() = default;
virtual void set_value(T &&value) {
set_result(std::move(value));
}
virtual void set_error(Status &&error) {
set_result(std::move(error));
}
virtual void set_result(Result &&result) {
if (result.is_ok()) {
set_value(result.move_as_ok());
} else {
set_error(result.move_as_error());
}
}
void operator()(T &&value) {
set_value(std::move(value));
}
void operator()(Status &&error) {
set_error(std::move(error));
}
void operator()(Result &&result) {
set_result(std::move(result));
}
};
template
class Promise;
constexpr std::false_type is_promise_interface(...) {
return {};
}
template
constexpr std::true_type is_promise_interface(const PromiseInterface &promise) {
return {};
}
template
constexpr std::true_type is_promise_interface(const Promise &promise) {
return {};
}
template
constexpr bool is_promise_interface() {
return decltype(is_promise_interface(std::declval()))::value;
}
constexpr std::false_type is_promise_interface_ptr(...) {
return {};
}
template
constexpr std::true_type is_promise_interface_ptr(const unique_ptr &promise) {
return {};
}
template
constexpr bool is_promise_interface_ptr() {
return decltype(is_promise_interface_ptr(std::declval()))::value;
}
template
class LambdaPromise : public PromiseInterface {
public:
using ArgT = ValueT;
void set_value(ValueT &&value) override {
CHECK(has_lambda_.get());
do_ok(std::move(value));
has_lambda_ = false;
}
void set_error(Status &&error) override {
CHECK(has_lambda_.get());
do_error(std::move(error));
has_lambda_ = false;
}
LambdaPromise(const LambdaPromise &other) = delete;
LambdaPromise &operator=(const LambdaPromise &other) = delete;
LambdaPromise(LambdaPromise &&other) = default;
LambdaPromise &operator=(LambdaPromise &&other) = default;
~LambdaPromise() override {
if (has_lambda_.get()) {
do_error(Status::Error("Lost promise"));
}
}
template
explicit LambdaPromise(FromOkT &&ok) : ok_(std::forward(ok)), has_lambda_(true) {
}
private:
FunctionT ok_;
MovableValue has_lambda_{false};
template
std::enable_if_t>::value, void> do_error(Status &&status) {
ok_(Result(std::move(status)));
}
template
std::enable_if_t>::value, void> do_error(Y &&status) {
ok_(Auto());
}
template
std::enable_if_t>::value, void> do_ok(ValueT &&result) {
ok_(Result(std::move(result)));
}
template
std::enable_if_t>::value, void> do_ok(ValueT &&result) {
ok_(std::move(result));
}
};
template ::value, bool> has_t = false>
auto lambda_promise(F &&f) {
return LambdaPromise>>, std::decay_t>(std::forward(f));
}
template ::value, bool> has_t = true>
auto lambda_promise(F &&f) {
return LambdaPromise>(std::forward(f));
}
template (), bool> from_promise_inerface = true>
auto &&promise_interface(F &&f) {
return std::forward(f);
}
template (), bool> from_promise_inerface = false>
auto promise_interface(F &&f) {
return lambda_promise(std::forward(f));
}
template (), bool> from_promise_inerface = true>
auto promise_interface_ptr(F &&f) {
return std::forward(f);
}
template (), bool> from_promise_inerface = false>
auto promise_interface_ptr(F &&f) {
return std::make_unique(std::forward(f)))>>(
promise_interface(std::forward(f)));
}
template
class Promise {
public:
using ArgT = T;
void set_value(T &&value) {
if (!promise_) {
return;
}
promise_->set_value(std::move(value));
promise_.reset();
}
void set_error(Status &&error) {
if (!promise_) {
return;
}
promise_->set_error(std::move(error));
promise_.reset();
}
void set_result(Result &&result) {
if (!promise_) {
return;
}
promise_->set_result(std::move(result));
promise_.reset();
}
template
void operator()(S &&result) {
if (!promise_) {
return;
}
promise_->operator()(std::forward(result));
promise_.reset();
}
void reset() {
promise_.reset();
}
std::unique_ptr> release() {
return std::move(promise_);
}
Promise() = default;
explicit Promise(std::unique_ptr> promise) : promise_(std::move(promise)) {
}
Promise &operator=(Promise &&) = default;
Promise(Promise &&) = default;
template
Promise(F &&f) : promise_(promise_interface_ptr(std::forward(f))) {
}
explicit operator bool() {
return static_cast(promise_);
}
template
auto do_wrap(V &&value, F &&func) {
if (value.is_ok()) {
set_result(func(value.move_as_ok()));
} else {
set_error(value.move_as_error());
}
}
template
auto do_wrap(td::Status status, F &&func) {
set_error(std::move(status));
}
template
auto wrap(F &&func) {
return [promise = std::move(*this), func = std::move(func)](auto &&res) mutable {
promise.do_wrap(std::move(res), std::move(func));
};
}
template
auto send_closure(ArgsT &&... args);
private:
std::unique_ptr> promise_;
};
namespace detail {
template
class JoinPromise : public PromiseInterface {
public:
explicit JoinPromise(ArgsT &&... arg) : promises_(std::forward(arg)...) {
}
void set_value(Unit &&) override {
tuple_for_each(promises_, [](auto &promise) { promise.set_value(Unit()); });
}
void set_error(Status &&error) override {
tuple_for_each(promises_, [&error](auto &promise) { promise.set_error(error.clone()); });
}
private:
std::tuple...> promises_;
};
} // namespace detail
class PromiseCreator {
public:
struct Ignore {
void operator()(Status &&error) {
error.ignore();
}
};
template
static auto lambda(OkT &&ok) {
return lambda_promise(std::forward(ok));
}
template
static Promise<> join(ArgsT &&... args) {
return Promise<>(std::make_unique>(std::forward(args)...));
}
};
template
auto make_promise(F &&f) {
using ValueT = typename decltype(PromiseCreator::lambda(std::move(f)))::ArgT;
return Promise(PromiseCreator::lambda(std::move(f)));
}
template
auto make_promise(Promise &&f) {
return std::move(f);
}
template
class SafePromise {
public:
SafePromise(Promise promise, Result result) : promise_(std::move(promise)), result_(std::move(result)) {
}
SafePromise(const SafePromise &other) = delete;
SafePromise &operator=(const SafePromise &other) = delete;
SafePromise(SafePromise &&other) = default;
SafePromise &operator=(SafePromise &&other) = default;
~SafePromise() {
if (promise_) {
promise_.set_result(std::move(result_));
}
}
Promise release() {
return std::move(promise_);
}
operator Promise() && {
return release();
}
private:
Promise promise_;
Result result_;
};
template
class PromiseMerger;
template
struct SplitPromise {
using PromiseT = decltype(make_promise(std::declval()));
using ArgT = typename PromiseT::ArgT;
template
static std::pair, Promise> split(std::pair);
template
static std::tuple...> split(std::tuple);
using SplittedT = decltype(split(std::declval()));
template
static PromiseMerger merger(std::pair);
template
static PromiseMerger merger(std::tuple);
using MergerT = decltype(merger(std::declval()));
};
template
class PromiseMerger : public std::enable_shared_from_this> {
public:
std::tuple...> args_;
PromiseT promise_;
PromiseMerger(PromiseT promise) : promise_(std::move(promise)) {
}
~PromiseMerger() {
td::Status status;
tuple_for_each(args_, [&status](auto &&arg) {
if (status.is_error()) {
return;
}
if (arg.is_error()) {
status = arg.move_as_error();
}
});
if (status.is_error()) {
promise_.set_error(std::move(status));
return;
}
call_tuple([this](auto &&... args) { promise_.set_value({args.move_as_ok()...}); }, std::move(args_));
}
template
Promise make_promise(T &arg) {
return [&arg, self = this->shared_from_this()](auto res) { arg = std::move(res); };
}
template
auto split() {
return call_tuple([this](auto &&... arg) { return R{this->make_promise(arg)...}; }, std::move(args_));
}
};
template
auto split_promise(F &&f) {
auto merger = std::make_shared::MergerT>(std::move(f));
return merger->template split::SplittedT>();
}
template
struct PromiseFuture {
Result> promise_;
Result result_;
~PromiseFuture() {
if (promise_.is_ok()) {
promise_.move_as_ok().set_result(std::move(result_));
} else {
LOG(ERROR) << "Lost PromiseFuture";
}
}
};
template
struct Future;
template
std::pair, Future> make_promise_future();
template
struct Future {
Promise> promise_;
Future(Promise> promise) : promise_(std::move(promise)) {
}
void finish(Promise promise) {
promise_.set_value(std::move(promise));
}
template
auto map(F &&f) {
using R = detail::drop_result_t()))>;
auto pf = make_promise_future();
promise_.set_value([p = std::move(pf.first), f = std::move(f)](Result res) mutable {
TRY_RESULT_PROMISE(p, x, std::move(res));
p.set_result(f(std::move(x)));
});
return std::move(pf.second);
}
template
auto fmap(F &&f) {
return flatten(map(std::move(f)));
}
template
static Future flatten(Future> ff) {
auto pf = make_promise_future();
ff.promise_.set_value([p = std::move(pf.first)](Result> r_f) mutable {
TRY_RESULT_PROMISE(p, f, std::move(r_f));
// Promise p
// Future f
f.promise_.set_value(std::move(p));
});
return std::move(pf.second);
}
};
template
Future make_future(T &&value) {
return Future([value = std::move(value)](Result> r_promise) mutable {
if (r_promise.is_ok()) {
r_promise.move_as_ok().set_value(std::move(value));
} else {
LOG(ERROR) << "Lost future";
}
});
}
template
std::pair, Future> make_promise_future() {
auto pf = std::make_shared>();
Future future([pf](Result> res) mutable { pf->promise_ = std::move(res); });
Promise promise = [pf = std::move(pf)](Result res) mutable { pf->result_ = std::move(res); };
return std::make_pair(std::move(promise), std::move(future));
}
} // namespace td