mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-02 01:09:04 +02:00
These are currently the only way that callback methods can return values. These should only be used called from outside the main thread. This means either an async Rust function or a sync Rust function that's marked as wrapped-async in the `uniffi.toml` config file. Differential Revision: https://phabricator.services.mozilla.com/D245597
112 lines
4.2 KiB
C++
112 lines
4.2 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "nsPrintfCString.h"
|
|
#include "nsString.h"
|
|
#include "nsThreadUtils.h"
|
|
#include "mozilla/uniffi/OwnedRustBuffer.h"
|
|
#include "mozilla/dom/RootedDictionary.h"
|
|
#include "mozilla/dom/Promise.h"
|
|
#include "mozilla/dom/UniFFIBinding.h"
|
|
#include "mozilla/uniffi/Callbacks.h"
|
|
#include "mozilla/Maybe.h"
|
|
#include "mozilla/Logging.h"
|
|
#include "mozilla/RefPtr.h"
|
|
#include "mozilla/UniquePtr.h"
|
|
|
|
namespace mozilla::uniffi {
|
|
extern mozilla::LazyLogModule gUniffiLogger;
|
|
|
|
void AsyncCallbackMethodHandlerBase::ScheduleAsyncCall(
|
|
UniquePtr<AsyncCallbackMethodHandlerBase> aHandler,
|
|
StaticRefPtr<dom::UniFFICallbackHandler>* aJsHandler) {
|
|
nsresult dispatchResult = NS_DispatchToMainThread(NS_NewRunnableFunction(
|
|
"UniFFI callback", [handler = std::move(aHandler),
|
|
aJsHandler]() MOZ_CAN_RUN_SCRIPT_BOUNDARY mutable {
|
|
auto reportError = MakeScopeExit([&handler] {
|
|
dom::RootedDictionary<dom::UniFFIScaffoldingCallResult> callResult(
|
|
dom::RootingCx());
|
|
callResult.mCode = dom::UniFFIScaffoldingCallCode::Internal_error;
|
|
handler->HandleReturn(callResult, IgnoreErrors());
|
|
});
|
|
|
|
// Take our own reference to the callback handler to ensure that it
|
|
// stays alive for the duration of this call
|
|
RefPtr<dom::UniFFICallbackHandler> jsHandler = *aJsHandler;
|
|
if (!jsHandler) {
|
|
MOZ_LOG(gUniffiLogger, LogLevel::Error,
|
|
("[%s] called, but JS handler not registered",
|
|
handler->mUniffiMethodName));
|
|
return;
|
|
}
|
|
|
|
JSObject* global = jsHandler->CallbackGlobalOrNull();
|
|
if (!global) {
|
|
MOZ_LOG(
|
|
gUniffiLogger, LogLevel::Error,
|
|
("[%s] JS handler has null global", handler->mUniffiMethodName));
|
|
return;
|
|
}
|
|
|
|
dom::AutoEntryScript aes(global, handler->mUniffiMethodName);
|
|
|
|
IgnoredErrorResult error;
|
|
RefPtr<dom::Promise> promise =
|
|
handler->MakeCall(aes.cx(), jsHandler, error);
|
|
if (error.Failed()) {
|
|
MOZ_LOG(
|
|
gUniffiLogger, LogLevel::Error,
|
|
("[%s] Error invoking JS handler", handler->mUniffiMethodName));
|
|
return;
|
|
}
|
|
|
|
reportError.release();
|
|
if (promise) {
|
|
auto promiseHandler = MakeRefPtr<PromiseHandler>(std::move(handler));
|
|
promise->AppendNativeHandler(promiseHandler);
|
|
}
|
|
}));
|
|
|
|
if (NS_FAILED(dispatchResult)) {
|
|
MOZ_LOG(gUniffiLogger, LogLevel::Error,
|
|
("[UniFFI] Error dispatching UniFFI callback task"));
|
|
}
|
|
}
|
|
|
|
MOZ_CAN_RUN_SCRIPT
|
|
already_AddRefed<dom::Promise> CallbackFreeHandler::MakeCall(
|
|
JSContext* aCx, dom::UniFFICallbackHandler* aJsHandler,
|
|
ErrorResult& aError) {
|
|
aJsHandler->Destroy(mUniffiHandle.IntoRust(), aError);
|
|
// CallbackFreeHandler works like a fire-and-forget callback and returns
|
|
// nullptr. There's no Rust code that's awaiting this result.
|
|
return nullptr;
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS0(AsyncCallbackMethodHandlerBase::PromiseHandler);
|
|
|
|
void AsyncCallbackMethodHandlerBase::PromiseHandler::ResolvedCallback(
|
|
JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv) {
|
|
dom::RootedDictionary<dom::UniFFIScaffoldingCallResult> callResult(aCx);
|
|
if (!callResult.Init(aCx, aValue)) {
|
|
JS_ClearPendingException(aCx);
|
|
MOZ_LOG(
|
|
gUniffiLogger, LogLevel::Error,
|
|
("[%s] callback method did not return a UniFFIScaffoldingCallResult",
|
|
mHandler->mUniffiMethodName));
|
|
callResult.mCode = dom::UniFFIScaffoldingCallCode::Internal_error;
|
|
}
|
|
mHandler->HandleReturn(callResult, aRv);
|
|
}
|
|
|
|
void AsyncCallbackMethodHandlerBase::PromiseHandler::RejectedCallback(
|
|
JSContext* aCx, JS::Handle<JS::Value>, ErrorResult& aRv) {
|
|
dom::RootedDictionary<dom::UniFFIScaffoldingCallResult> callResult(aCx);
|
|
callResult.mCode = dom::UniFFIScaffoldingCallCode::Internal_error;
|
|
mHandler->HandleReturn(callResult, aRv);
|
|
}
|
|
|
|
} // namespace mozilla::uniffi
|