/* 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