/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include #include #include #include #include namespace facebook::react { template class AsyncPromise { public: AsyncPromise(jsi::Runtime &rt, const std::shared_ptr &jsInvoker) : state_(std::make_shared()) { auto constructor = rt.global().getPropertyAsFunction(rt, "Promise"); auto promise = constructor.callAsConstructor( rt, bridging::toJs( rt, // Safe to capture this since this is called synchronously. [this](AsyncCallback resolve, AsyncCallback reject) { state_->resolve = std::move(resolve); state_->reject = std::move(reject); }, jsInvoker)); auto promiseHolder = std::make_shared(promise.asObject(rt)); LongLivedObjectCollection::get().add(promiseHolder); // The shared state can retain the promise holder weakly now. state_->promiseHolder = promiseHolder; } void resolve(T value) { std::lock_guard lock(state_->mutex); if (state_->resolve) { state_->resolve->call(std::move(value)); state_->resolve.reset(); state_->reject.reset(); } } void reject(Error error) { std::lock_guard lock(state_->mutex); if (state_->reject) { state_->reject->call(std::move(error)); state_->reject.reset(); state_->resolve.reset(); } } jsi::Object get(jsi::Runtime &rt) const { if (auto holder = state_->promiseHolder.lock()) { return jsi::Value(rt, holder->promise).asObject(rt); } else { throw jsi::JSError(rt, "Failed to get invalidated promise"); } } private: struct PromiseHolder : LongLivedObject { PromiseHolder(jsi::Object p) : promise(std::move(p)) {} jsi::Object promise; }; struct SharedState { ~SharedState() { if (auto holder = promiseHolder.lock()) { holder->allowRelease(); } } std::mutex mutex; std::weak_ptr promiseHolder; std::optional> resolve; std::optional> reject; }; std::shared_ptr state_; }; template struct Bridging> { static jsi::Object toJs(jsi::Runtime &rt, const AsyncPromise &promise) { return promise.get(rt); } }; } // namespace facebook::react