/* 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-2019 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 using get_arg_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: 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_); } private: std::unique_ptr> promise_; }; template auto make_promise(F &&f) { using ValueT = detail::drop_result_t>; return Promise(promise_interface_ptr(std::forward(f))); } 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 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_; }; } // namespace td