/* * 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. */ #include namespace folly { namespace fibers { template Promise::Promise(folly::Try& value, BatonT& baton) : value_(&value), baton_(&baton) {} template Promise::Promise(Promise&& other) noexcept : value_(other.value_), baton_(other.baton_) { other.value_ = nullptr; other.baton_ = nullptr; } template Promise& Promise::operator=(Promise&& other) { std::swap(value_, other.value_); std::swap(baton_, other.baton_); return *this; } template void Promise::throwIfFulfilled() const { if (!value_) { throw std::logic_error("promise already fulfilled"); } } template Promise::~Promise() { if (value_) { setException(folly::make_exception_wrapper( "promise not fulfilled")); } } template void Promise::setException(folly::exception_wrapper e) { setTry(folly::Try(e)); } template void Promise::setTry(folly::Try&& t) { throwIfFulfilled(); *value_ = std::move(t); value_ = nullptr; // Baton::post has to be the last step here, since if Promise is not owned by // the posting thread, it may be destroyed right after Baton::post is called. baton_->post(); } template template void Promise::setValue(M&& v) { static_assert(!std::is_same::value, "Use setValue() instead"); setTry(folly::Try(std::forward(v))); } template void Promise::setValue() { static_assert(std::is_same::value, "Use setValue(value) instead"); setTry(folly::Try()); } template template void Promise::setWith(F&& func) { setTry(makeTryWith(std::forward(func))); } template template typename Promise::value_type Promise::await_async( F&& func) { folly::Try result; std::exception_ptr funcException; BatonT baton; baton.wait([&func, &result, &baton, &funcException]() mutable { try { func(Promise(result, baton)); } catch (...) { // Save the exception, but still wait for baton to be posted by user code // or promise destructor. funcException = std::current_exception(); } }); if (UNLIKELY(funcException != nullptr)) { std::rethrow_exception(funcException); } return std::move(result).value(); } } // namespace fibers } // namespace folly