/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include namespace folly { namespace futures { namespace detail { template void coreDetachPromiseMaybeWithResult(Core& core) { if (!core.hasResult()) { core.setResult(Try(exception_wrapper(BrokenPromise(pretty_name())))); } core.detachPromise(); } template void setTry(Promise& p, Executor::KeepAlive<>&& ka, Try&& t) { p.setTry(std::move(ka), std::move(t)); } } // namespace detail } // namespace futures template Promise Promise::makeEmpty() noexcept { return Promise(futures::detail::EmptyConstruct{}); } template Promise::Promise() : retrieved_(false), core_(Core::make()) {} template Promise::Promise(Promise&& other) noexcept : retrieved_(std::exchange(other.retrieved_, false)), core_(std::exchange(other.core_, nullptr)) {} template Promise& Promise::operator=(Promise&& other) noexcept { detach(); retrieved_ = std::exchange(other.retrieved_, false); core_ = std::exchange(other.core_, nullptr); return *this; } template void Promise::throwIfFulfilled() const { if (getCore().hasResult()) { throw_exception(); } } template Promise::Promise(futures::detail::EmptyConstruct) noexcept : retrieved_(false), core_(nullptr) {} template Promise::~Promise() { detach(); } template void Promise::detach() { if (core_) { if (!retrieved_) { core_->detachFuture(); } futures::detail::coreDetachPromiseMaybeWithResult(*core_); core_ = nullptr; } } template SemiFuture Promise::getSemiFuture() { if (retrieved_) { throw_exception(); } retrieved_ = true; return SemiFuture(&getCore()); } template Future Promise::getFuture() { // An InlineExecutor approximates the old behaviour of continuations // running inine on setting the value of the promise. return getSemiFuture().via(&InlineExecutor::instance()); } template template typename std::enable_if::value>::type Promise::setException(E const& e) { setException(make_exception_wrapper(e)); } template void Promise::setException(exception_wrapper ew) { setTry(Try(std::move(ew))); } template template void Promise::setInterruptHandler(F&& fn) { getCore().setInterruptHandler(std::forward(fn)); } template void Promise::setTry(Try&& t) { throwIfFulfilled(); core_->setResult(std::move(t)); } template void Promise::setTry(Executor::KeepAlive<>&& ka, Try&& t) { throwIfFulfilled(); core_->setResult(std::move(ka), std::move(t)); } template template void Promise::setValue(M&& v) { static_assert(!std::is_same::value, "Use setValue() instead"); setTry(Try(std::forward(v))); } template template void Promise::setWith(F&& func) { throwIfFulfilled(); setTry(makeTryWith(std::forward(func))); } template bool Promise::isFulfilled() const noexcept { if (core_) { return core_->hasResult(); } return true; } } // namespace folly