Backed out 2 changesets (bug 1951243, bug 1951241) for causing bustages on GeneratedScaffolding.cpp . CLOSED TREE
Backed out changeset 944bac64c3db (bug 1951243) Backed out changeset c79b66ed7283 (bug 1951241)
This commit is contained in:
@@ -69,7 +69,8 @@ xpcom/reflect/xptcall/md/unix/.*
|
||||
# Askama template code, which isn't valid C++ in its original form
|
||||
toolkit/components/uniffi-bindgen-gecko-js/src/templates/.*
|
||||
# Generated from that template code
|
||||
toolkit/components/uniffi-js/GeneratedScaffolding.cpp
|
||||
toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp
|
||||
toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp
|
||||
|
||||
# Generated from ./tools/rewriting/ThirdPartyPaths.txt
|
||||
# awk '{print ""$1".*"}' ./tools/rewriting/ThirdPartyPaths.txt
|
||||
|
||||
@@ -1563,7 +1563,8 @@ toolkit/components/nimbus/schemas/ExperimentFeatureManifest.schema.json
|
||||
toolkit/components/nimbus/schemas/NimbusExperiment.schema.json
|
||||
toolkit/components/pdfjs/PdfJsDefaultPrefs.js
|
||||
toolkit/components/pdfjs/PdfJsOverridePrefs.js
|
||||
toolkit/components/uniffi-js/GeneratedScaffolding.cpp
|
||||
toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp
|
||||
toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp
|
||||
toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated
|
||||
tools/@types/tspaths.json
|
||||
tools/browsertime/package.json
|
||||
|
||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2524,7 +2524,6 @@ dependencies = [
|
||||
name = "gkrust-uniffi-components"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"hashbrown 0.15.2",
|
||||
"relevancy",
|
||||
"search",
|
||||
"suggest",
|
||||
|
||||
@@ -22,8 +22,6 @@ search = "0.1"
|
||||
suggest = "0.1"
|
||||
relevancy = "0.1"
|
||||
webext-storage = "0.1"
|
||||
# Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1959469
|
||||
hashbrown = { version = "0.15.2", features = [ "default-hasher" ] }
|
||||
|
||||
[features]
|
||||
# Should we depend on xpcom crates?
|
||||
|
||||
@@ -7,7 +7,7 @@ import subprocess
|
||||
|
||||
from mach.decorators import Command, SubCommand
|
||||
|
||||
CPP_PATH = "toolkit/components/uniffi-js/GeneratedScaffolding.cpp"
|
||||
CPP_PATH = "toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp"
|
||||
JS_DIR = "toolkit/components/uniffi-bindgen-gecko-js/components/generated"
|
||||
FIXTURE_JS_DIR = "toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated"
|
||||
DOCS_PATH = "docs/rust-components/api/js/"
|
||||
|
||||
@@ -93,7 +93,7 @@ impl CPPScaffoldingTemplate {
|
||||
arg_types: ffi_func
|
||||
.arguments()
|
||||
.iter()
|
||||
.map(|a| ffi_type_name(&a.type_()))
|
||||
.map(|a| cpp_type(&a.type_()))
|
||||
.chain(
|
||||
ffi_func
|
||||
.has_rust_call_status_arg()
|
||||
@@ -108,7 +108,7 @@ impl CPPScaffoldingTemplate {
|
||||
arg_types: ffi_callback
|
||||
.arguments()
|
||||
.into_iter()
|
||||
.map(|a| ffi_type_name(&a.type_()))
|
||||
.map(|a| cpp_type(&a.type_()))
|
||||
.chain(
|
||||
ffi_callback
|
||||
.has_rust_call_status_arg()
|
||||
@@ -125,7 +125,7 @@ impl CPPScaffoldingTemplate {
|
||||
.into_iter()
|
||||
.map(|f| FfiFieldCpp {
|
||||
name: f.name().to_snake_case(),
|
||||
type_: ffi_type_name(&f.type_()),
|
||||
type_: cpp_type(&f.type_()),
|
||||
})
|
||||
.collect(),
|
||||
}),
|
||||
@@ -182,7 +182,7 @@ impl CPPScaffoldingTemplate {
|
||||
let cbi_name_snake = cbi.name().to_snake_case();
|
||||
|
||||
CallbackInterfaceVTable {
|
||||
type_: ffi_type_name(&cbi.vtable()),
|
||||
type_: cpp_type(&cbi.vtable()),
|
||||
var_name: format!("kCallbackInterfaceVtable{cbi_name}"),
|
||||
method_handlers: cbi
|
||||
.vtable_methods()
|
||||
@@ -196,13 +196,13 @@ impl CPPScaffoldingTemplate {
|
||||
arguments: method
|
||||
.arguments()
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
let ffi_type = arg.as_type().into();
|
||||
CallbackMethodArgument {
|
||||
.map(|arg| CallbackMethodArgument {
|
||||
name: arg.name().to_snake_case(),
|
||||
ffi_type: ffi_type_name(&ffi_type),
|
||||
ffi_value_class: ffi_value_class(ci, &ffi_type),
|
||||
}
|
||||
type_: cpp_type(&arg.as_type().into()),
|
||||
scaffolding_converter: scaffolding_converter(
|
||||
ci,
|
||||
&arg.as_type().into(),
|
||||
),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
@@ -337,8 +337,8 @@ struct CallbackMethodHandler {
|
||||
|
||||
struct CallbackMethodArgument {
|
||||
name: String,
|
||||
ffi_type: String,
|
||||
ffi_value_class: String,
|
||||
type_: String,
|
||||
scaffolding_converter: String,
|
||||
}
|
||||
|
||||
struct ScaffoldingCall {
|
||||
@@ -366,7 +366,7 @@ impl ScaffoldingCall {
|
||||
.into_iter()
|
||||
.map(|a| ScaffoldingCallArgument {
|
||||
var_name: format!("m{}", a.name().to_upper_camel_case()),
|
||||
ffi_value_class: ffi_value_class(ci, &a.type_()),
|
||||
scaffolding_converter: scaffolding_converter(ci, &a.type_()),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
@@ -384,9 +384,8 @@ impl ScaffoldingCall {
|
||||
// function always returns a handle.
|
||||
return_type: callable
|
||||
.return_type()
|
||||
.map(|return_type| FfiType::from(return_type))
|
||||
.map(|return_type| ScaffoldingCallReturnType {
|
||||
ffi_value_class: ffi_value_class(ci, &return_type),
|
||||
scaffolding_converter: scaffolding_converter(ci, &return_type.into()),
|
||||
}),
|
||||
arguments,
|
||||
async_info,
|
||||
@@ -399,12 +398,12 @@ impl ScaffoldingCall {
|
||||
}
|
||||
|
||||
struct ScaffoldingCallReturnType {
|
||||
ffi_value_class: String,
|
||||
scaffolding_converter: String,
|
||||
}
|
||||
|
||||
struct ScaffoldingCallArgument {
|
||||
var_name: String,
|
||||
ffi_value_class: String,
|
||||
scaffolding_converter: String,
|
||||
}
|
||||
|
||||
struct ScaffoldingCallAsyncInfo {
|
||||
@@ -413,7 +412,7 @@ struct ScaffoldingCallAsyncInfo {
|
||||
free_fn: String,
|
||||
}
|
||||
|
||||
fn ffi_value_class(ci: &ComponentInterface, ffi_type: &FfiType) -> String {
|
||||
fn scaffolding_converter(ci: &ComponentInterface, ffi_type: &FfiType) -> String {
|
||||
match ffi_type {
|
||||
FfiType::RustArcPtr(name) => {
|
||||
// Check if this is an external type
|
||||
@@ -422,29 +421,17 @@ fn ffi_value_class(ci: &ComponentInterface, ffi_type: &FfiType) -> String {
|
||||
let crate_name = ty.module_path().expect("External type without module path");
|
||||
if external_ty_name == name {
|
||||
return format!(
|
||||
"FfiValueObjectHandle<&{}>",
|
||||
"ScaffoldingObjectConverter<&{}>",
|
||||
pointer_type(crate_name_to_namespace(&crate_name), name),
|
||||
);
|
||||
}
|
||||
}
|
||||
format!(
|
||||
"FfiValueObjectHandle<&{}>",
|
||||
"ScaffoldingObjectConverter<&{}>",
|
||||
pointer_type(ci.namespace(), name),
|
||||
)
|
||||
}
|
||||
FfiType::UInt8
|
||||
| FfiType::Int8
|
||||
| FfiType::UInt16
|
||||
| FfiType::Int16
|
||||
| FfiType::UInt32
|
||||
| FfiType::Int32
|
||||
| FfiType::UInt64
|
||||
| FfiType::Int64 => format!("FfiValueInt<{}>", ffi_type_name(ffi_type)),
|
||||
FfiType::Float32 | FfiType::Float64 => {
|
||||
format!("FfiValueFloat<{}>", ffi_type_name(ffi_type))
|
||||
}
|
||||
FfiType::RustBuffer(_) => "FfiValueRustBuffer".to_owned(),
|
||||
_ => format!("FfiConverter<{}>", ffi_type_name(ffi_type)),
|
||||
_ => format!("ScaffoldingConverter<{}>", cpp_type(ffi_type)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,8 +443,8 @@ fn pointer_type(namespace: &str, name: &str) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
// C++ type for an FFI value
|
||||
fn ffi_type_name(ffi_type: &FfiType) -> String {
|
||||
// Type for the Rust scaffolding code
|
||||
fn cpp_type(ffi_type: &FfiType) -> String {
|
||||
match ffi_type {
|
||||
FfiType::UInt8 => "uint8_t".to_owned(),
|
||||
FfiType::Int8 => "int8_t".to_owned(),
|
||||
@@ -477,14 +464,14 @@ fn ffi_type_name(ffi_type: &FfiType) -> String {
|
||||
FfiType::Callback(name) | FfiType::Struct(name) => name.to_owned(),
|
||||
FfiType::VoidPointer => "void*".to_owned(),
|
||||
FfiType::MutReference(inner) | FfiType::Reference(inner) => {
|
||||
format!("{}*", ffi_type_name(inner.as_ref()))
|
||||
format!("{}*", cpp_type(inner.as_ref()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn return_type(ffi_type: Option<&FfiType>) -> String {
|
||||
match ffi_type {
|
||||
Some(t) => ffi_type_name(t),
|
||||
Some(t) => cpp_type(t),
|
||||
None => "void".to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/ScaffoldingConverter.h"
|
||||
#include "mozilla/dom/UniFFICall.h"
|
||||
#include "mozilla/dom/UniFFICallbacks.h"
|
||||
#include "mozilla/dom/UniFFIPointerType.h"
|
||||
#include "mozilla/dom/UniFFIScaffolding.h"
|
||||
#include "mozilla/uniffi/Call.h"
|
||||
#include "mozilla/uniffi/Callbacks.h"
|
||||
#include "mozilla/uniffi/FfiValue.h"
|
||||
#include "mozilla/uniffi/PointerType.h"
|
||||
#include "mozilla/uniffi/Rust.h"
|
||||
#include "mozilla/dom/UniFFIRust.h"
|
||||
|
||||
namespace mozilla::uniffi {
|
||||
|
||||
@@ -78,15 +78,15 @@ static StaticRefPtr<dom::UniFFICallbackHandler> {{ cbi.js_handler_var }};
|
||||
|
||||
class {{ handler.class_name }} : public UniffiCallbackMethodHandlerBase {
|
||||
private:
|
||||
// Rust arguments
|
||||
// Rust arguments, converted using ScaffoldingConverter::FromRust.
|
||||
{%- for a in handler.arguments %}
|
||||
{{ a.ffi_value_class }} {{ a.name }}{};
|
||||
typename {{ a.scaffolding_converter }}::IntermediateType {{ a.name }};
|
||||
{%- endfor %}
|
||||
|
||||
public:
|
||||
{{ handler.class_name }}(size_t aObjectHandle{%- for a in handler.arguments %}, {{ a.ffi_type }} {{ a.name }}{%- endfor %})
|
||||
{{ handler.class_name }}(size_t aObjectHandle{%- for a in handler.arguments %}, {{ a.type_ }} {{ a.name }}{%- endfor %})
|
||||
: UniffiCallbackMethodHandlerBase("{{ cbi.name }}", aObjectHandle)
|
||||
{%- for a in handler.arguments %}, {{ a.name }}({{ a.ffi_value_class }}::FromRust({{ a.name }})){% endfor %} {
|
||||
{%- for a in handler.arguments %}, {{ a.name }}({{ a.scaffolding_converter }}::FromRust({{ a.name }})){% endfor %} {
|
||||
}
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
@@ -102,8 +102,9 @@ public:
|
||||
|
||||
// Convert each argument
|
||||
{%- for a in handler.arguments %}
|
||||
{{ a.name }}.Lift(
|
||||
{{ a.scaffolding_converter }}::IntoJs(
|
||||
aCx,
|
||||
std::move(this->{{ a.name }}),
|
||||
&uniffiArgs[{{ loop.index0 }}],
|
||||
aError);
|
||||
if (aError.Failed()) {
|
||||
@@ -122,7 +123,7 @@ public:
|
||||
|
||||
extern "C" void {{ handler.fn_name }}(
|
||||
uint64_t uniffiHandle,
|
||||
{% for a in handler.arguments %}{{ a.ffi_type }} {{ a.name }}, {% endfor %}
|
||||
{% for a in handler.arguments %}{{ a.type_ }} {{ a.name }}, {% endfor %}
|
||||
void* uniffiOutReturn,
|
||||
RustCallStatus* uniffiCallStatus
|
||||
) {
|
||||
@@ -220,22 +221,22 @@ void DeregisterCallbackHandler(uint64_t aInterfaceId, ErrorResult& aError) {
|
||||
{%- when None %}
|
||||
class {{ scaffolding_call.handler_class_name }} : public UniffiSyncCallHandler {
|
||||
private:
|
||||
// LowerRustArgs stores the resulting arguments in these fields
|
||||
// PrepareRustArgs stores the resulting arguments in these fields
|
||||
{%- for arg in scaffolding_call.arguments %}
|
||||
{{ arg.ffi_value_class }} {{ arg.var_name }}{};
|
||||
typename {{ arg.scaffolding_converter }}::IntermediateType {{ arg.var_name }};
|
||||
{%- endfor %}
|
||||
|
||||
// MakeRustCall stores the result of the call in these fields
|
||||
{%- match scaffolding_call.return_type %}
|
||||
{%- when Some(return_type) %}
|
||||
{{ return_type.ffi_value_class }} mUniffiReturnValue{};
|
||||
typename {{ return_type.scaffolding_converter }}::IntermediateType mUniffiReturnValue;
|
||||
{%- else %}
|
||||
{%- endmatch %}
|
||||
|
||||
public:
|
||||
void LowerRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override {
|
||||
void PrepareRustArgs(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override {
|
||||
{%- for arg in scaffolding_call.arguments %}
|
||||
{{ arg.var_name }}.Lower(aArgs[{{ loop.index0 }}], aError);
|
||||
{{ arg.scaffolding_converter }}::FromJs(aArgs[{{ loop.index0 }}], &{{ arg.var_name }}, aError);
|
||||
if (aError.Failed()) {
|
||||
return;
|
||||
}
|
||||
@@ -245,10 +246,10 @@ public:
|
||||
void MakeRustCall(RustCallStatus* aOutStatus) override {
|
||||
{%- match scaffolding_call.return_type %}
|
||||
{%- when Some(return_type) %}
|
||||
mUniffiReturnValue = {{ return_type.ffi_value_class }}::FromRust(
|
||||
mUniffiReturnValue = {{ return_type.scaffolding_converter }}::FromRust(
|
||||
{{ scaffolding_call.ffi_func_name }}(
|
||||
{%- for arg in scaffolding_call.arguments %}
|
||||
{{ arg.var_name }}.IntoRust(),
|
||||
{{ arg.scaffolding_converter }}::IntoRust(std::move({{ arg.var_name }})),
|
||||
{%- endfor %}
|
||||
aOutStatus
|
||||
)
|
||||
@@ -256,18 +257,19 @@ public:
|
||||
{%- else %}
|
||||
{{ scaffolding_call.ffi_func_name }}(
|
||||
{%- for arg in scaffolding_call.arguments %}
|
||||
{{ arg.var_name }}.IntoRust(),
|
||||
{{ arg.scaffolding_converter }}::IntoRust(std::move({{ arg.var_name }})),
|
||||
{%- endfor %}
|
||||
aOutStatus
|
||||
);
|
||||
{%- endmatch %}
|
||||
}
|
||||
|
||||
virtual void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override {
|
||||
virtual void ExtractSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override {
|
||||
{%- match scaffolding_call.return_type %}
|
||||
{%- when Some(return_type) %}
|
||||
mUniffiReturnValue.Lift(
|
||||
{{ return_type.scaffolding_converter }}::IntoJs(
|
||||
aCx,
|
||||
std::move(mUniffiReturnValue),
|
||||
&aDest.Construct(),
|
||||
aError
|
||||
);
|
||||
@@ -284,7 +286,7 @@ private:
|
||||
// Complete stores the result of the call in mUniffiReturnValue
|
||||
{%- match scaffolding_call.return_type %}
|
||||
{%- when Some(return_type) %}
|
||||
{{ return_type.ffi_value_class }} mUniffiReturnValue{};
|
||||
typename {{ return_type.scaffolding_converter }}::IntermediateType mUniffiReturnValue;
|
||||
{%- else %}
|
||||
{%- endmatch %}
|
||||
|
||||
@@ -292,10 +294,10 @@ protected:
|
||||
// Convert a sequence of JS arguments and call the scaffolding function.
|
||||
// Always called on the main thread since async Rust calls don't block, they
|
||||
// return a future.
|
||||
void LowerArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override {
|
||||
void PrepareArgsAndMakeRustCall(const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs, ErrorResult& aError) override {
|
||||
{%- for arg in scaffolding_call.arguments %}
|
||||
{{ arg.ffi_value_class }} {{ arg.var_name }}{};
|
||||
{{ arg.var_name }}.Lower(aArgs[{{ loop.index0 }}], aError);
|
||||
typename {{ arg.scaffolding_converter }}::IntermediateType {{ arg.var_name }};
|
||||
{{ arg.scaffolding_converter }}::FromJs(aArgs[{{ loop.index0 }}], &{{ arg.var_name }}, aError);
|
||||
if (aError.Failed()) {
|
||||
return;
|
||||
}
|
||||
@@ -303,7 +305,7 @@ protected:
|
||||
|
||||
mFutureHandle = {{ scaffolding_call.ffi_func_name }}(
|
||||
{%- for arg in scaffolding_call.arguments %}
|
||||
{{ arg.var_name }}.IntoRust(){% if !loop.last %},{% endif %}
|
||||
{{ arg.scaffolding_converter }}::IntoRust(std::move({{ arg.var_name }})){% if !loop.last %},{% endif %}
|
||||
{%- endfor %}
|
||||
);
|
||||
}
|
||||
@@ -311,7 +313,7 @@ protected:
|
||||
void CallCompleteFn(RustCallStatus* aOutStatus) override {
|
||||
{%- match scaffolding_call.return_type %}
|
||||
{%- when Some(return_type) %}
|
||||
mUniffiReturnValue = {{ return_type.ffi_value_class }}::FromRust(
|
||||
mUniffiReturnValue = {{ return_type.scaffolding_converter }}::FromRust(
|
||||
{{ async_info.complete_fn }}(mFutureHandle, aOutStatus));
|
||||
{%- else %}
|
||||
{{ async_info.complete_fn }}(mFutureHandle, aOutStatus);
|
||||
@@ -319,11 +321,12 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
void LiftSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override {
|
||||
void ExtractSuccessfulCallResult(JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest, ErrorResult& aError) override {
|
||||
{%- match scaffolding_call.return_type %}
|
||||
{%- when Some(return_type) %}
|
||||
mUniffiReturnValue.Lift(
|
||||
{{ return_type.scaffolding_converter }}::IntoJs(
|
||||
aCx,
|
||||
std::move(mUniffiReturnValue),
|
||||
&aDest.Construct(),
|
||||
aError
|
||||
);
|
||||
|
||||
@@ -1,226 +0,0 @@
|
||||
/* -*- 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 "nsThreadUtils.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/RootedDictionary.h"
|
||||
#include "mozilla/uniffi/Call.h"
|
||||
#include "mozilla/uniffi/ResultPromise.h"
|
||||
|
||||
namespace mozilla::uniffi {
|
||||
extern mozilla::LazyLogModule gUniffiLogger;
|
||||
|
||||
using dom::GlobalObject;
|
||||
using dom::OwningUniFFIScaffoldingValue;
|
||||
using dom::RootedDictionary;
|
||||
using dom::Sequence;
|
||||
using dom::UniFFIScaffoldingCallResult;
|
||||
|
||||
void UniffiSyncCallHandler::CallSync(
|
||||
UniquePtr<UniffiSyncCallHandler> aHandler, const GlobalObject& aGlobal,
|
||||
const Sequence<OwningUniFFIScaffoldingValue>& aArgs,
|
||||
RootedDictionary<UniFFIScaffoldingCallResult>& aReturnValue,
|
||||
ErrorResult& aError) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
aHandler->LowerRustArgs(aArgs, aError);
|
||||
if (aError.Failed()) {
|
||||
return;
|
||||
}
|
||||
RustCallStatus callStatus{};
|
||||
aHandler->MakeRustCall(&callStatus);
|
||||
aHandler->mUniffiCallStatusCode = callStatus.code;
|
||||
if (callStatus.error_buf.data) {
|
||||
aHandler->mUniffiCallStatusErrorBuf =
|
||||
FfiValueRustBuffer(callStatus.error_buf);
|
||||
}
|
||||
aHandler->LiftCallResult(aGlobal.Context(), aReturnValue, aError);
|
||||
}
|
||||
|
||||
already_AddRefed<dom::Promise> UniffiSyncCallHandler::CallAsyncWrapper(
|
||||
UniquePtr<UniffiSyncCallHandler> aHandler, const dom::GlobalObject& aGlobal,
|
||||
const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs,
|
||||
ErrorResult& aError) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
aHandler->LowerRustArgs(aArgs, aError);
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uniffi::ResultPromise resultPromise;
|
||||
resultPromise.Init(aGlobal, aError);
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsresult dispatchResult = NS_DispatchBackgroundTask(
|
||||
NS_NewRunnableFunction("UniffiSyncCallHandler::CallAsyncWrapper",
|
||||
[handler = std::move(aHandler),
|
||||
resultPromise = resultPromise]() mutable {
|
||||
RustCallStatus callStatus{};
|
||||
handler->MakeRustCall(&callStatus);
|
||||
handler->mUniffiCallStatusCode = callStatus.code;
|
||||
if (callStatus.error_buf.data) {
|
||||
handler->mUniffiCallStatusErrorBuf =
|
||||
FfiValueRustBuffer(callStatus.error_buf);
|
||||
}
|
||||
|
||||
resultPromise.Complete(std::move(handler));
|
||||
}),
|
||||
NS_DISPATCH_EVENT_MAY_BLOCK);
|
||||
if (NS_FAILED(dispatchResult)) {
|
||||
MOZ_LOG(gUniffiLogger, LogLevel::Error,
|
||||
("[UniFFI] NS_DispatchBackgroundTask failed"));
|
||||
resultPromise.RejectWithUnexpectedError();
|
||||
}
|
||||
|
||||
return do_AddRef(resultPromise.GetPromise());
|
||||
}
|
||||
|
||||
void UniffiCallHandlerBase::LiftCallResult(
|
||||
JSContext* aCx,
|
||||
dom::RootedDictionary<dom::UniFFIScaffoldingCallResult>& aDest,
|
||||
ErrorResult& aError) {
|
||||
switch (mUniffiCallStatusCode) {
|
||||
case RUST_CALL_SUCCESS: {
|
||||
aDest.mCode = dom::UniFFIScaffoldingCallCode::Success;
|
||||
LiftSuccessfulCallResult(aCx, aDest.mData, aError);
|
||||
break;
|
||||
}
|
||||
|
||||
case RUST_CALL_ERROR: {
|
||||
// Rust Err() value. Populate data with the `RustBuffer` containing the
|
||||
// error
|
||||
aDest.mCode = dom::UniFFIScaffoldingCallCode::Error;
|
||||
mUniffiCallStatusErrorBuf.Lift(aCx, &aDest.mData.Construct(), aError);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
// This indicates a RustError, which should rarely happen in practice.
|
||||
// The normal case is a Rust panic, but FF sets panic=abort.
|
||||
aDest.mCode = dom::UniFFIScaffoldingCallCode::Internal_error;
|
||||
if (mUniffiCallStatusErrorBuf.IsSet()) {
|
||||
mUniffiCallStatusErrorBuf.Lift(aCx, &aDest.mData.Construct(), aError);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<dom::Promise> UniffiAsyncCallHandler::CallAsync(
|
||||
UniquePtr<UniffiAsyncCallHandler> aHandler,
|
||||
const dom::GlobalObject& aGlobal,
|
||||
const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs,
|
||||
ErrorResult& aError) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// Async calls return a Future rather than doing any work. This means we can
|
||||
// make the call right now on the JS main thread without fear of blocking it.
|
||||
aHandler->LowerArgsAndMakeRustCall(aArgs, aError);
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aHandler->mPromise.Init(aGlobal, aError);
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ResultPromise returnPromise(aHandler->mPromise);
|
||||
|
||||
// Schedule a poll for the future in a background thread.
|
||||
nsresult dispatchResult = NS_DispatchBackgroundTask(
|
||||
NS_NewRunnableFunction("UniffiAsyncCallHandler::CallAsync",
|
||||
[handler = std::move(aHandler)]() mutable {
|
||||
UniffiAsyncCallHandler::Poll(std::move(handler));
|
||||
}));
|
||||
if (NS_FAILED(dispatchResult)) {
|
||||
MOZ_LOG(gUniffiLogger, LogLevel::Error,
|
||||
("[UniFFI] NS_DispatchBackgroundTask failed"));
|
||||
aHandler->mPromise.RejectWithUnexpectedError();
|
||||
}
|
||||
|
||||
return do_AddRef(returnPromise.GetPromise());
|
||||
}
|
||||
|
||||
// Callback function for async calls
|
||||
//
|
||||
// This is passed to Rust when we poll the future alongside a 64-bit handle that
|
||||
// represents the callback data. For uniffi-bindgen-gecko-js, the handle is a
|
||||
// `UniffiAsyncCallHandler*` casted to an int.
|
||||
//
|
||||
// Rust calls this when either the future is ready or when it's time to poll it
|
||||
// again.
|
||||
void UniffiAsyncCallHandler::FutureCallback(uint64_t aCallHandlerHandle,
|
||||
int8_t aCode) {
|
||||
// Recreate the UniquePtr we previously released
|
||||
UniquePtr<UniffiAsyncCallHandler> handler(
|
||||
reinterpret_cast<UniffiAsyncCallHandler*>(
|
||||
static_cast<uintptr_t>(aCallHandlerHandle)));
|
||||
|
||||
switch (aCode) {
|
||||
case UNIFFI_FUTURE_READY: {
|
||||
// `Future::poll` returned a `Ready` value on the Rust side.
|
||||
// Complete the future
|
||||
RustCallStatus callStatus{};
|
||||
handler->CallCompleteFn(&callStatus);
|
||||
handler->mUniffiCallStatusCode = callStatus.code;
|
||||
if (callStatus.error_buf.data) {
|
||||
handler->mUniffiCallStatusErrorBuf =
|
||||
FfiValueRustBuffer(callStatus.error_buf);
|
||||
}
|
||||
// Copy of the ResultPromise before moving the handler that contains it.
|
||||
ResultPromise promise(handler->mPromise);
|
||||
promise.Complete(std::move(handler));
|
||||
break;
|
||||
}
|
||||
|
||||
case UNIFFI_FUTURE_MAYBE_READY: {
|
||||
// The Rust waker was invoked after `poll` returned a `Pending` value.
|
||||
// Poll the future again soon in a background task.
|
||||
|
||||
nsresult dispatchResult =
|
||||
NS_DispatchBackgroundTask(NS_NewRunnableFunction(
|
||||
"UniffiAsyncCallHandler::FutureCallback",
|
||||
[handler = std::move(handler)]() mutable {
|
||||
UniffiAsyncCallHandler::Poll(std::move(handler));
|
||||
}));
|
||||
if (NS_FAILED(dispatchResult)) {
|
||||
MOZ_LOG(gUniffiLogger, LogLevel::Error,
|
||||
("[UniFFI] NS_DispatchBackgroundTask failed"));
|
||||
handler->mPromise.RejectWithUnexpectedError();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
// Invalid poll code, this should never happen, but if it does log an
|
||||
// error and reject the promise.
|
||||
MOZ_LOG(gUniffiLogger, LogLevel::Error,
|
||||
("[UniFFI] Invalid poll code in "
|
||||
"UniffiAsyncCallHandler::FutureCallback %d",
|
||||
aCode));
|
||||
handler->mPromise.RejectWithUnexpectedError();
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void UniffiAsyncCallHandler::Poll(UniquePtr<UniffiAsyncCallHandler> aHandler) {
|
||||
auto futureHandle = aHandler->mFutureHandle;
|
||||
auto pollFn = aHandler->mPollFn;
|
||||
// Release the UniquePtr into a raw pointer and convert it to a handle
|
||||
// so that we can pass it as a handle to the UniFFI code. It gets converted
|
||||
// back in `UniffiAsyncCallHandler::FutureCallback()`, which the Rust code
|
||||
// guarentees will be called if the future makes progress.
|
||||
uint64_t selfHandle =
|
||||
static_cast<uint64_t>(reinterpret_cast<uintptr_t>(aHandler.release()));
|
||||
pollFn(futureHandle, UniffiAsyncCallHandler::FutureCallback, selfHandle);
|
||||
}
|
||||
|
||||
UniffiAsyncCallHandler::~UniffiAsyncCallHandler() { mFreeFn(mFutureHandle); }
|
||||
|
||||
} // namespace mozilla::uniffi
|
||||
@@ -1,231 +0,0 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_UniFFIFfiConverter_h
|
||||
#define mozilla_UniFFIFfiConverter_h
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include "nsString.h"
|
||||
#include "mozilla/ResultVariant.h"
|
||||
#include "mozilla/dom/PrimitiveConversions.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "mozilla/dom/UniFFIBinding.h"
|
||||
#include "mozilla/dom/UniFFIPointer.h"
|
||||
#include "mozilla/dom/UniFFIScaffolding.h"
|
||||
#include "mozilla/uniffi/OwnedRustBuffer.h"
|
||||
#include "mozilla/uniffi/PointerType.h"
|
||||
#include "mozilla/uniffi/Rust.h"
|
||||
|
||||
namespace mozilla::uniffi {
|
||||
|
||||
// This header defines the `FfiValue*` classes, which handle conversions between
|
||||
// FFI values and the JS `OwningUniFFIScaffoldingValue` class.
|
||||
//
|
||||
// The exact signatures vary slightly, but in all FfiValue classes define these
|
||||
// functions:
|
||||
// - `Lower` -- Convert a `OwningUniFFIScaffoldingValue` into an `FfiValue`.
|
||||
// - `Lift` -- Convert a `FfiValue` into a `OwningUniFFIScaffoldingValue`.
|
||||
// - `IntoRust` -- Convert a `FfiValue` into a raw FFI type to pass to Rust
|
||||
// - `FromRust` -- Convert a raw FFI type from Rust into a `FfiValue`
|
||||
//
|
||||
// Also, each `FfiValue` class defines a default constructor.
|
||||
// For types that hold resources like `FfiValueRustBuffer`, `Lift` and
|
||||
// `IntoRust` move resources out of the value, leaving behind the default.
|
||||
|
||||
// FfiValue class for integer values
|
||||
template <typename T>
|
||||
class FfiValueInt {
|
||||
private:
|
||||
T mValue = 0;
|
||||
|
||||
public:
|
||||
FfiValueInt() = default;
|
||||
explicit FfiValueInt(T aValue) : mValue(aValue) {}
|
||||
|
||||
void Lower(const dom::OwningUniFFIScaffoldingValue& aValue,
|
||||
ErrorResult& aError) {
|
||||
if (!aValue.IsDouble()) {
|
||||
aError.ThrowTypeError("Bad argument type"_ns);
|
||||
return;
|
||||
}
|
||||
double floatValue = aValue.GetAsDouble();
|
||||
|
||||
// Use PrimitiveConversionTraits_Limits rather than std::numeric_limits,
|
||||
// since it handles JS-specific bounds like the 64-bit integer limits.
|
||||
// (see Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER)
|
||||
if (floatValue < dom::PrimitiveConversionTraits_Limits<T>::min() ||
|
||||
floatValue > dom::PrimitiveConversionTraits_Limits<T>::max()) {
|
||||
aError.ThrowRangeError("Integer value is out of range"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
T intValue = static_cast<T>(floatValue);
|
||||
if (intValue != floatValue) {
|
||||
aError.ThrowTypeError("Not an integer"_ns);
|
||||
return;
|
||||
}
|
||||
mValue = intValue;
|
||||
}
|
||||
|
||||
void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest,
|
||||
ErrorResult& aError) {
|
||||
if (mValue < dom::PrimitiveConversionTraits_Limits<T>::min() ||
|
||||
mValue > dom::PrimitiveConversionTraits_Limits<T>::max()) {
|
||||
aError.ThrowRangeError(
|
||||
"64-bit value cannot be precisely represented in JS"_ns);
|
||||
return;
|
||||
}
|
||||
aDest->SetAsDouble() = mValue;
|
||||
}
|
||||
|
||||
T IntoRust() { return mValue; }
|
||||
|
||||
static FfiValueInt FromRust(T aValue) { return FfiValueInt(aValue); };
|
||||
};
|
||||
|
||||
// FfiValue class for floating point values
|
||||
template <typename T>
|
||||
class FfiValueFloat {
|
||||
private:
|
||||
T mValue = 0.0;
|
||||
|
||||
public:
|
||||
FfiValueFloat() = default;
|
||||
explicit FfiValueFloat(T aValue) : mValue(aValue) {}
|
||||
|
||||
void Lower(const dom::OwningUniFFIScaffoldingValue& aValue,
|
||||
ErrorResult& aError) {
|
||||
if (!aValue.IsDouble()) {
|
||||
aError.ThrowTypeError("Bad argument type"_ns);
|
||||
return;
|
||||
}
|
||||
mValue = aValue.GetAsDouble();
|
||||
}
|
||||
|
||||
void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest,
|
||||
ErrorResult& aError) {
|
||||
aDest->SetAsDouble() = mValue;
|
||||
}
|
||||
|
||||
T IntoRust() { return mValue; }
|
||||
|
||||
static FfiValueFloat FromRust(T aValue) { return FfiValueFloat(aValue); }
|
||||
};
|
||||
|
||||
class FfiValueRustBuffer {
|
||||
private:
|
||||
OwnedRustBuffer mValue;
|
||||
|
||||
public:
|
||||
FfiValueRustBuffer() = default;
|
||||
explicit FfiValueRustBuffer(RustBuffer aValue)
|
||||
: mValue(OwnedRustBuffer(aValue)) {}
|
||||
explicit FfiValueRustBuffer(OwnedRustBuffer aValue)
|
||||
: mValue(std::move(aValue)) {}
|
||||
|
||||
void Lower(const dom::OwningUniFFIScaffoldingValue& aValue,
|
||||
ErrorResult& aError) {
|
||||
if (!aValue.IsArrayBuffer()) {
|
||||
aError.ThrowTypeError("Expected ArrayBuffer argument"_ns);
|
||||
return;
|
||||
}
|
||||
mValue = OwnedRustBuffer::FromArrayBuffer(aValue.GetAsArrayBuffer());
|
||||
}
|
||||
|
||||
void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest,
|
||||
ErrorResult& aError) {
|
||||
JS::Rooted<JSObject*> obj(aContext);
|
||||
mValue.IntoArrayBuffer(aContext, &obj, aError);
|
||||
if (aError.Failed()) {
|
||||
return;
|
||||
}
|
||||
aDest->SetAsArrayBuffer().Init(obj);
|
||||
}
|
||||
|
||||
RustBuffer IntoRust() { return mValue.IntoRustBuffer(); }
|
||||
|
||||
static FfiValueRustBuffer FromRust(RustBuffer aValue) {
|
||||
return FfiValueRustBuffer(OwnedRustBuffer(aValue));
|
||||
}
|
||||
|
||||
bool IsSet() { return mValue.IsValid(); }
|
||||
};
|
||||
|
||||
template <const UniFFIPointerType* PointerType>
|
||||
class FfiValueObjectHandle {
|
||||
private:
|
||||
void* mValue = nullptr;
|
||||
|
||||
public:
|
||||
FfiValueObjectHandle() = default;
|
||||
explicit FfiValueObjectHandle(void* aValue) : mValue(aValue) {}
|
||||
|
||||
// Delete copy constructor and assignment as this type is non-copyable.
|
||||
FfiValueObjectHandle(const FfiValueObjectHandle&) = delete;
|
||||
FfiValueObjectHandle& operator=(const FfiValueObjectHandle&) = delete;
|
||||
|
||||
FfiValueObjectHandle& operator=(FfiValueObjectHandle&& aOther) {
|
||||
if (mValue && mValue != aOther.mValue) {
|
||||
FreeHandle();
|
||||
}
|
||||
mValue = aOther.mValue;
|
||||
aOther.mValue = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Lower(const dom::OwningUniFFIScaffoldingValue& aValue,
|
||||
ErrorResult& aError) {
|
||||
if (!aValue.IsUniFFIPointer()) {
|
||||
aError.ThrowTypeError("Expected UniFFI pointer argument"_ns);
|
||||
return;
|
||||
}
|
||||
dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer();
|
||||
if (!value.IsSamePtrType(PointerType)) {
|
||||
aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns);
|
||||
return;
|
||||
}
|
||||
FreeHandle();
|
||||
mValue = value.ClonePtr();
|
||||
}
|
||||
|
||||
void Lift(JSContext* aContext, dom::OwningUniFFIScaffoldingValue* aDest,
|
||||
ErrorResult& aError) {
|
||||
aDest->SetAsUniFFIPointer() =
|
||||
dom::UniFFIPointer::Create(mValue, PointerType);
|
||||
mValue = nullptr;
|
||||
}
|
||||
|
||||
void* IntoRust() {
|
||||
auto temp = mValue;
|
||||
mValue = nullptr;
|
||||
return temp;
|
||||
}
|
||||
|
||||
static FfiValueObjectHandle FromRust(void* aValue) {
|
||||
return FfiValueObjectHandle(aValue);
|
||||
}
|
||||
|
||||
void FreeHandle() {
|
||||
if (mValue) {
|
||||
RustCallStatus callStatus{};
|
||||
(PointerType->destructor)(mValue, &callStatus);
|
||||
// No need to check `RustCallStatus`, it's only part of the API to match
|
||||
// other FFI calls. The free function can never fail.
|
||||
}
|
||||
}
|
||||
|
||||
~FfiValueObjectHandle() {
|
||||
// If the pointer is non-null, this means Lift/IntoRust was never called
|
||||
// because there was some failure along the way. Free the pointer to avoid a
|
||||
// leak
|
||||
FreeHandle();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mozilla::uniffi
|
||||
|
||||
#endif // mozilla_UniFFIFfiConverter_h
|
||||
@@ -5,7 +5,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsString.h"
|
||||
#include "mozilla/uniffi/OwnedRustBuffer.h"
|
||||
#include "mozilla/dom/OwnedRustBuffer.h"
|
||||
|
||||
namespace mozilla::uniffi {
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "mozilla/uniffi/Rust.h"
|
||||
#include "mozilla/dom/UniFFIRust.h"
|
||||
|
||||
namespace mozilla::uniffi {
|
||||
|
||||
|
||||
@@ -2,3 +2,17 @@
|
||||
|
||||
This directory contains C++ helper code for the UniFFI Rust library
|
||||
(https://github.com/mozilla/uniffi-rs/).
|
||||
|
||||
- `UniFFIPointer.*` and `UniFFIPointerType.*` implement the `UniFFIPointer` WebIDL class
|
||||
|
||||
- `UniFFI*Scaffolding.cpp` implements the `UniFFIScaffolding` WebIDL class.
|
||||
- UniFFIGeneratedScaffolding.cpp contains the generated C++ code
|
||||
- UniFFIScaffolding.cpp is a facade that wraps UniFFIFixtureScaffolding, and
|
||||
UniFFIGeneratedScaffolding if enabled, to implement the interface.
|
||||
|
||||
- `ScaffoldingConverter.h` contain helper code to convert values between JS and Rust. This is used
|
||||
by the generated code to make scaffolding calls.
|
||||
|
||||
- `OwnedRustBuffer.*` implements a C++ class to help manager ownership of a RustBuffer.
|
||||
|
||||
- `UniFFIRust.h` contains definitions for the C functions that UniFFI exports.
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/uniffi/Call.h"
|
||||
#include "mozilla/uniffi/ResultPromise.h"
|
||||
|
||||
namespace mozilla::uniffi {
|
||||
|
||||
void ResultPromise::Init(const dom::GlobalObject& aGlobal,
|
||||
ErrorResult& aError) {
|
||||
nsCOMPtr<nsIGlobalObject> xpcomGlobal =
|
||||
do_QueryInterface(aGlobal.GetAsSupports());
|
||||
RefPtr<dom::Promise> promise = dom::Promise::Create(xpcomGlobal, aError);
|
||||
if (aError.Failed()) {
|
||||
return;
|
||||
}
|
||||
mPromise =
|
||||
new nsMainThreadPtrHolder<dom::Promise>("uniffi::ResultPromise", promise);
|
||||
}
|
||||
|
||||
void ResultPromise::Complete(UniquePtr<UniffiCallHandlerBase> aHandler) {
|
||||
MOZ_ASSERT(mPromise);
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"uniffi::ResultPromise::Complete",
|
||||
[promise = mPromise, handler = std::move(aHandler)]() {
|
||||
dom::AutoEntryScript aes(promise->GetGlobalObject(),
|
||||
"uniffi::ResultPromise::Complete");
|
||||
dom::RootedDictionary<dom::UniFFIScaffoldingCallResult> returnValue(
|
||||
aes.cx());
|
||||
|
||||
ErrorResult error;
|
||||
handler->LiftCallResult(aes.cx(), returnValue, error);
|
||||
error.WouldReportJSException();
|
||||
if (error.Failed()) {
|
||||
promise->MaybeReject(std::move(error));
|
||||
} else {
|
||||
promise->MaybeResolve(returnValue);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void ResultPromise::RejectWithUnexpectedError() {
|
||||
MOZ_ASSERT(mPromise);
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
"uniffi::ResultPromise::RejectWithUnexpectedError", [promise = mPromise] {
|
||||
promise->MaybeRejectWithUnknownError(
|
||||
"UniFFI Unexpected Internal Error");
|
||||
}));
|
||||
}
|
||||
|
||||
} // namespace mozilla::uniffi
|
||||
@@ -1,68 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_UniFFIResultPromise_h
|
||||
#define mozilla_dom_UniFFIResultPromise_h
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/UniFFIBinding.h"
|
||||
|
||||
namespace mozilla::uniffi {
|
||||
extern mozilla::LazyLogModule gUniffiLogger;
|
||||
|
||||
class UniffiAsyncCallHandler;
|
||||
class UniffiCallHandlerBase;
|
||||
|
||||
/**
|
||||
* JS "bridge" for UniFFI
|
||||
*
|
||||
* This module intefaces with the SpiderMonkey JS API so that other code can
|
||||
* focus on the core UniFFI logic.
|
||||
*/
|
||||
|
||||
class ResultPromise {
|
||||
public:
|
||||
ResultPromise() = default;
|
||||
|
||||
// Initialize a ResultPromise, this must be done before calling any other
|
||||
// methods.
|
||||
//
|
||||
// This must be called on the main thread.
|
||||
void Init(const dom::GlobalObject& aGlobal, ErrorResult& aError);
|
||||
|
||||
// Get a raw `dom::Promise` pointer
|
||||
//
|
||||
// Use this to return the promise from a webidl-generated function.
|
||||
// May only be called on the main thread.
|
||||
dom::Promise* GetPromise() { return mPromise; }
|
||||
|
||||
// Complete the promise using a call handler, this can be called from any
|
||||
// thread.
|
||||
//
|
||||
// After a promise is completed, it must not be used anymore.
|
||||
void Complete(UniquePtr<UniffiCallHandlerBase> aHandler);
|
||||
|
||||
// Reject the promise with an unexpected error.
|
||||
//
|
||||
// Use this as a last resort, when something has gone very wrong in the FFI.
|
||||
//
|
||||
// After a promise is rejected, it must not be used anymore.
|
||||
void RejectWithUnexpectedError();
|
||||
|
||||
private:
|
||||
// The `nsMainThreadPtrHandle` ensures that if this type is destroyed
|
||||
// from off-main-thread, it'll actually be released on the main thread.
|
||||
// This is important because the promise is a main-thread-only object.
|
||||
nsMainThreadPtrHandle<dom::Promise> mPromise;
|
||||
};
|
||||
|
||||
} // namespace mozilla::uniffi
|
||||
|
||||
#endif // mozilla_dom_UniFFIResultPromise_h
|
||||
211
toolkit/components/uniffi-js/ScaffoldingConverter.h
Normal file
211
toolkit/components/uniffi-js/ScaffoldingConverter.h
Normal file
@@ -0,0 +1,211 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_ScaffoldingConverter_h
|
||||
#define mozilla_ScaffoldingConverter_h
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include "nsString.h"
|
||||
#include "mozilla/ResultVariant.h"
|
||||
#include "mozilla/dom/OwnedRustBuffer.h"
|
||||
#include "mozilla/dom/PrimitiveConversions.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "mozilla/dom/UniFFIBinding.h"
|
||||
#include "mozilla/dom/UniFFIPointer.h"
|
||||
#include "mozilla/dom/UniFFIPointerType.h"
|
||||
#include "mozilla/dom/UniFFIRust.h"
|
||||
#include "mozilla/dom/UniFFIScaffolding.h"
|
||||
|
||||
namespace mozilla::uniffi {
|
||||
|
||||
// Handle converting types between JS and Rust
|
||||
//
|
||||
// Scaffolding conversions are done using a 2 step process:
|
||||
// - Call FromJs/FromRust to convert to an intermediate type
|
||||
// - Call IntoJs/IntoRust to convert from that type to the target type
|
||||
//
|
||||
// The main reason for this is handling RustBuffers when other arguments fail
|
||||
// to convert. By using OwnedRustBuffer as the intermediate type, we can
|
||||
// ensure those buffers get freed in that case. Note that we can't use
|
||||
// OwnedRustBuffer as the Rust type. Passing the buffer into Rust transfers
|
||||
// ownership so we shouldn't free the buffer in this case.
|
||||
//
|
||||
// For most other types, we just use the Rust type as the intermediate type.
|
||||
template <typename T>
|
||||
class ScaffoldingConverter {
|
||||
public:
|
||||
using RustType = T;
|
||||
using IntermediateType = T;
|
||||
|
||||
// Convert a JS value to an intermedate type
|
||||
//
|
||||
// This inputs a const ref, because that's what the WebIDL bindings send to
|
||||
// us.
|
||||
//
|
||||
// If this succeeds then IntoRust is also guaranteed to succeed
|
||||
static void FromJs(const dom::OwningUniFFIScaffoldingValue& aValue,
|
||||
IntermediateType* aResult, ErrorResult& aError) {
|
||||
if (!aValue.IsDouble()) {
|
||||
aError.ThrowTypeError("Bad argument type"_ns);
|
||||
return;
|
||||
}
|
||||
double value = aValue.GetAsDouble();
|
||||
|
||||
if (std::isnan(value)) {
|
||||
aError.ThrowUnknownError("NaN not allowed"_ns);
|
||||
return;
|
||||
}
|
||||
|
||||
if constexpr (std::is_integral<RustType>::value) {
|
||||
// Use PrimitiveConversionTraits_Limits rather than std::numeric_limits,
|
||||
// since it handles JS-specific bounds like the 64-bit integer limits.
|
||||
// (see Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER)
|
||||
if (value < dom::PrimitiveConversionTraits_Limits<RustType>::min() ||
|
||||
value > dom::PrimitiveConversionTraits_Limits<RustType>::max()) {
|
||||
aError.ThrowRangeError(
|
||||
"UniFFI return value cannot be precisely represented in JS"_ns);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't check float bounds for a few reasons.
|
||||
// - It's difficult because
|
||||
// PrimitiveConversionTraits_Limits<float>::min() is the smallest
|
||||
// positive value, rather than the most negative.
|
||||
// - A float value unlikely to overflow
|
||||
// - It's also likely that we can't do an exact conversion because the
|
||||
// float doesn't have enough precision, but it doesn't seem correct
|
||||
// to error out in that case.
|
||||
|
||||
IntermediateType rv = static_cast<IntermediateType>(value);
|
||||
if constexpr (std::is_integral<IntermediateType>::value) {
|
||||
if (rv != value) {
|
||||
aError.ThrowTypeError("Not an integer"_ns);
|
||||
return;
|
||||
}
|
||||
}
|
||||
*aResult = rv;
|
||||
}
|
||||
|
||||
// Convert an intermediate type to a Rust type
|
||||
//
|
||||
// IntoRust doesn't touch the JS data, so it's safe to call in a worker thread
|
||||
static RustType IntoRust(IntermediateType aValue) { return aValue; }
|
||||
|
||||
// Convert an Rust type to an intermediate type
|
||||
//
|
||||
// This inputs a value since Rust types are POD types
|
||||
static IntermediateType FromRust(RustType aValue) { return aValue; }
|
||||
|
||||
// Convert an intermedate type to a JS type
|
||||
//
|
||||
// This inputs an r-value reference since we may want to move data out of
|
||||
// this type.
|
||||
static void IntoJs(JSContext* aContext, IntermediateType&& aValue,
|
||||
dom::OwningUniFFIScaffoldingValue* aDest,
|
||||
ErrorResult& aError) {
|
||||
if constexpr (std::is_same<RustType, int64_t>::value ||
|
||||
std::is_same<RustType, uint64_t>::value) {
|
||||
// Check that the value can fit in a double (only needed for 64 bit types)
|
||||
if (aValue < dom::PrimitiveConversionTraits_Limits<RustType>::min() ||
|
||||
aValue > dom::PrimitiveConversionTraits_Limits<RustType>::max()) {
|
||||
aError.ThrowRangeError(
|
||||
"UniFFI return value cannot be precisely represented in JS"_ns);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if constexpr (std::is_floating_point<RustType>::value) {
|
||||
if (std::isnan(aValue)) {
|
||||
aError.ThrowUnknownError("NaN not allowed"_ns);
|
||||
return;
|
||||
}
|
||||
}
|
||||
aDest->SetAsDouble() = aValue;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class ScaffoldingConverter<RustBuffer> {
|
||||
public:
|
||||
using RustType = RustBuffer;
|
||||
using IntermediateType = OwnedRustBuffer;
|
||||
|
||||
static void FromJs(const dom::OwningUniFFIScaffoldingValue& aValue,
|
||||
OwnedRustBuffer* aResult, ErrorResult& aError) {
|
||||
if (!aValue.IsArrayBuffer()) {
|
||||
aError.ThrowTypeError("Expected ArrayBuffer argument"_ns);
|
||||
return;
|
||||
}
|
||||
*aResult = OwnedRustBuffer::FromArrayBuffer(aValue.GetAsArrayBuffer());
|
||||
}
|
||||
|
||||
static RustBuffer IntoRust(OwnedRustBuffer&& aValue) {
|
||||
return aValue.IntoRustBuffer();
|
||||
}
|
||||
|
||||
static OwnedRustBuffer FromRust(RustBuffer aValue) {
|
||||
return OwnedRustBuffer(aValue);
|
||||
}
|
||||
|
||||
static void IntoJs(JSContext* aContext, OwnedRustBuffer&& aValue,
|
||||
dom::OwningUniFFIScaffoldingValue* aDest,
|
||||
ErrorResult& aError) {
|
||||
JS::Rooted<JSObject*> obj(aContext);
|
||||
aValue.IntoArrayBuffer(aContext, &obj, aError);
|
||||
if (aError.Failed()) {
|
||||
return;
|
||||
}
|
||||
aDest->SetAsArrayBuffer().Init(obj);
|
||||
}
|
||||
};
|
||||
|
||||
// ScaffoldingConverter for object pointers
|
||||
template <const UniFFIPointerType* PointerType>
|
||||
class ScaffoldingObjectConverter {
|
||||
public:
|
||||
using RustType = void*;
|
||||
using IntermediateType = void*;
|
||||
|
||||
static void FromJs(const dom::OwningUniFFIScaffoldingValue& aValue,
|
||||
void** aResult, ErrorResult& aError) {
|
||||
if (!aValue.IsUniFFIPointer()) {
|
||||
aError.ThrowTypeError("Expected UniFFI pointer argument"_ns);
|
||||
return;
|
||||
}
|
||||
dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer();
|
||||
if (!value.IsSamePtrType(PointerType)) {
|
||||
aError.ThrowTypeError("Incorrect UniFFI pointer type"_ns);
|
||||
return;
|
||||
}
|
||||
*aResult = value.ClonePtr();
|
||||
}
|
||||
|
||||
static void* IntoRust(void* aValue) { return aValue; }
|
||||
|
||||
static void* FromRust(void* aValue) { return aValue; }
|
||||
|
||||
static void IntoJs(JSContext* aContext, void* aValue,
|
||||
dom::OwningUniFFIScaffoldingValue* aDest,
|
||||
ErrorResult& aError) {
|
||||
aDest->SetAsUniFFIPointer() =
|
||||
dom::UniFFIPointer::Create(aValue, PointerType);
|
||||
}
|
||||
};
|
||||
|
||||
// ScaffoldingConverter for void returns
|
||||
//
|
||||
// This doesn't implement the normal interface, it's only use is a the
|
||||
// ReturnConverter parameter of ScaffoldingCallHandler.
|
||||
template <>
|
||||
class ScaffoldingConverter<void> {
|
||||
public:
|
||||
using RustType = void;
|
||||
};
|
||||
|
||||
} // namespace mozilla::uniffi
|
||||
|
||||
#endif // mozilla_ScaffoldingConverter_h
|
||||
299
toolkit/components/uniffi-js/UniFFICall.cpp
Normal file
299
toolkit/components/uniffi-js/UniFFICall.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
/* -*- 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 "nsThreadUtils.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/RootedDictionary.h"
|
||||
#include "mozilla/dom/UniFFICall.h"
|
||||
|
||||
namespace mozilla::uniffi {
|
||||
extern mozilla::LazyLogModule gUniffiLogger;
|
||||
|
||||
using dom::GlobalObject;
|
||||
using dom::OwningUniFFIScaffoldingValue;
|
||||
using dom::RootedDictionary;
|
||||
using dom::Sequence;
|
||||
using dom::UniFFIScaffoldingCallResult;
|
||||
|
||||
void UniffiSyncCallHandler::CallSync(
|
||||
UniquePtr<UniffiSyncCallHandler> aHandler, const GlobalObject& aGlobal,
|
||||
const Sequence<OwningUniFFIScaffoldingValue>& aArgs,
|
||||
RootedDictionary<UniFFIScaffoldingCallResult>& aReturnValue,
|
||||
ErrorResult& aError) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
aHandler->PrepareRustArgs(aArgs, aError);
|
||||
if (aError.Failed()) {
|
||||
return;
|
||||
}
|
||||
RustCallStatus callStatus{};
|
||||
aHandler->MakeRustCall(&callStatus);
|
||||
aHandler->mUniffiCallStatusCode = callStatus.code;
|
||||
if (callStatus.error_buf.data) {
|
||||
aHandler->mUniffiCallStatusErrorBuf = OwnedRustBuffer(callStatus.error_buf);
|
||||
}
|
||||
aHandler->ExtractCallResult(aGlobal.Context(), aReturnValue, aError);
|
||||
}
|
||||
|
||||
already_AddRefed<dom::Promise> UniffiSyncCallHandler::CallAsyncWrapper(
|
||||
UniquePtr<UniffiSyncCallHandler> aHandler, const dom::GlobalObject& aGlobal,
|
||||
const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs,
|
||||
ErrorResult& aError) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
aHandler->PrepareRustArgs(aArgs, aError);
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create the promise that we return to JS
|
||||
nsCOMPtr<nsIGlobalObject> xpcomGlobal =
|
||||
do_QueryInterface(aGlobal.GetAsSupports());
|
||||
RefPtr<dom::Promise> returnPromise =
|
||||
dom::Promise::Create(xpcomGlobal, aError);
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create a second promise that gets resolved by a background task that
|
||||
// calls the scaffolding function
|
||||
RefPtr taskPromise =
|
||||
new MozPromise<UniquePtr<UniffiSyncCallHandler>, nsresult, true>::Private(
|
||||
__func__);
|
||||
|
||||
nsresult dispatchResult = NS_DispatchBackgroundTask(
|
||||
NS_NewRunnableFunction(
|
||||
__func__,
|
||||
[handler = std::move(aHandler), taskPromise]() mutable {
|
||||
RustCallStatus callStatus{};
|
||||
handler->MakeRustCall(&callStatus);
|
||||
handler->mUniffiCallStatusCode = callStatus.code;
|
||||
if (callStatus.error_buf.data) {
|
||||
handler->mUniffiCallStatusErrorBuf =
|
||||
OwnedRustBuffer(callStatus.error_buf);
|
||||
}
|
||||
taskPromise->Resolve(std::move(handler), __func__);
|
||||
}),
|
||||
NS_DISPATCH_EVENT_MAY_BLOCK);
|
||||
if (NS_FAILED(dispatchResult)) {
|
||||
taskPromise->Reject(dispatchResult, __func__);
|
||||
}
|
||||
|
||||
// When the background task promise completes, resolve the JS promise
|
||||
taskPromise->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[xpcomGlobal, returnPromise](
|
||||
typename MozPromise<UniquePtr<UniffiSyncCallHandler>, nsresult,
|
||||
true>::ResolveOrRejectValue&& aResult) {
|
||||
if (!aResult.IsResolve()) {
|
||||
returnPromise->MaybeRejectWithUnknownError(__func__);
|
||||
return;
|
||||
}
|
||||
auto handler = std::move(aResult.ResolveValue());
|
||||
dom::AutoEntryScript aes(xpcomGlobal,
|
||||
"UniffiSyncCallHandler::CallAsyncWrapper");
|
||||
dom::RootedDictionary<dom::UniFFIScaffoldingCallResult> returnValue(
|
||||
aes.cx());
|
||||
|
||||
ErrorResult error;
|
||||
handler->ExtractCallResult(aes.cx(), returnValue, error);
|
||||
error.WouldReportJSException();
|
||||
if (error.Failed()) {
|
||||
returnPromise->MaybeReject(std::move(error));
|
||||
} else {
|
||||
returnPromise->MaybeResolve(returnValue);
|
||||
}
|
||||
});
|
||||
|
||||
// Return the JS promise, using forget() to convert it to already_AddRefed
|
||||
return returnPromise.forget();
|
||||
}
|
||||
|
||||
void UniffiCallHandlerBase::ExtractCallResult(
|
||||
JSContext* aCx,
|
||||
dom::RootedDictionary<dom::UniFFIScaffoldingCallResult>& aDest,
|
||||
ErrorResult& aError) {
|
||||
switch (mUniffiCallStatusCode) {
|
||||
case RUST_CALL_SUCCESS: {
|
||||
aDest.mCode = dom::UniFFIScaffoldingCallCode::Success;
|
||||
ExtractSuccessfulCallResult(aCx, aDest.mData, aError);
|
||||
break;
|
||||
}
|
||||
|
||||
case RUST_CALL_ERROR: {
|
||||
// Rust Err() value. Populate data with the `RustBuffer` containing the
|
||||
// error
|
||||
aDest.mCode = dom::UniFFIScaffoldingCallCode::Error;
|
||||
|
||||
JS::Rooted<JSObject*> obj(aCx);
|
||||
mUniffiCallStatusErrorBuf.IntoArrayBuffer(aCx, &obj, aError);
|
||||
if (aError.Failed()) {
|
||||
break;
|
||||
}
|
||||
aDest.mData.Construct().SetAsArrayBuffer().Init(obj);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
// This indicates a RustError, which should rarely happen in practice.
|
||||
// The normal case is a Rust panic, but FF sets panic=abort.
|
||||
aDest.mCode = dom::UniFFIScaffoldingCallCode::Internal_error;
|
||||
if (mUniffiCallStatusErrorBuf.IsValid()) {
|
||||
JS::Rooted<JSObject*> obj(aCx);
|
||||
mUniffiCallStatusErrorBuf.IntoArrayBuffer(aCx, &obj, aError);
|
||||
if (aError.Failed()) {
|
||||
break;
|
||||
}
|
||||
aDest.mData.Construct().SetAsArrayBuffer().Init(obj);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<dom::Promise> UniffiAsyncCallHandler::CallAsync(
|
||||
UniquePtr<UniffiAsyncCallHandler> aHandler,
|
||||
const dom::GlobalObject& aGlobal,
|
||||
const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs,
|
||||
ErrorResult& aError) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// Async calls return a Future rather than doing any work. This means we can
|
||||
// make the call right now on the JS main thread without fear of blocking it.
|
||||
aHandler->PrepareArgsAndMakeRustCall(aArgs, aError);
|
||||
if (aError.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Create the promise that the handler will resolve
|
||||
nsCOMPtr<nsIGlobalObject> global(do_QueryInterface(aGlobal.GetAsSupports()));
|
||||
aHandler->mPromise = dom::Promise::Create(global, aError);
|
||||
// Also get a copy to return to JS
|
||||
RefPtr<dom::Promise> returnPromise(aHandler->mPromise);
|
||||
|
||||
if (aError.Failed()) {
|
||||
aError.ThrowUnknownError("[UniFFI] dom::Promise::Create failed"_ns);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Schedule a poll for the future in a background thread.
|
||||
nsresult dispatchResult = NS_DispatchBackgroundTask(NS_NewRunnableFunction(
|
||||
__func__, [handler = std::move(aHandler)]() mutable {
|
||||
UniffiAsyncCallHandler::Poll(std::move(handler));
|
||||
}));
|
||||
if (NS_FAILED(dispatchResult)) {
|
||||
aError.ThrowUnknownError(
|
||||
"[UniFFI] UniffiAsyncCallHandler::CallAsync - Error scheduling background task"_ns);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Return a copy of the JS promise, using forget() to convert it to
|
||||
// already_AddRefed
|
||||
return returnPromise.forget();
|
||||
}
|
||||
|
||||
// Callback function for async calls
|
||||
//
|
||||
// This is passed to Rust when we poll the future alongside a 64-bit handle that
|
||||
// represents the callback data. For uniffi-bindgen-gecko-js, the handle is a
|
||||
// `UniffiAsyncCallHandler*` casted to an int.
|
||||
//
|
||||
// Rust calls this when either the future is ready or when it's time to poll it
|
||||
// again.
|
||||
void UniffiAsyncCallHandler::FutureCallback(uint64_t aCallHandlerHandle,
|
||||
int8_t aCode) {
|
||||
// Recreate the UniquePtr we previously released
|
||||
UniquePtr<UniffiAsyncCallHandler> handler(
|
||||
reinterpret_cast<UniffiAsyncCallHandler*>(
|
||||
static_cast<uintptr_t>(aCallHandlerHandle)));
|
||||
|
||||
switch (aCode) {
|
||||
case UNIFFI_FUTURE_READY: {
|
||||
// `Future::poll` returned a `Ready` value on the Rust side.
|
||||
nsresult dispatchResult = NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
__func__, [handler = std::move(handler)]() mutable {
|
||||
UniffiAsyncCallHandler::Finish(std::move(handler));
|
||||
}));
|
||||
if (NS_FAILED(dispatchResult)) {
|
||||
MOZ_LOG(gUniffiLogger, LogLevel::Error,
|
||||
("[UniFFI] NS_DispatchToMainThread failed in "
|
||||
"UniffiAsyncCallHandler::FutureCallback"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case UNIFFI_FUTURE_MAYBE_READY: {
|
||||
// The Rust waker was invoked after `poll` returned a `Pending` value.
|
||||
// Poll the future again soon in a background task.
|
||||
nsresult dispatchResult = NS_DispatchBackgroundTask(
|
||||
NS_NewRunnableFunction(__func__,
|
||||
[handler = std::move(handler)]() mutable {
|
||||
UniffiAsyncCallHandler::Poll(
|
||||
std::move(handler));
|
||||
}),
|
||||
NS_DISPATCH_NORMAL);
|
||||
if (NS_FAILED(dispatchResult)) {
|
||||
MOZ_LOG(gUniffiLogger, LogLevel::Error,
|
||||
("[UniFFI] NS_DispatchBackgroundTask failed in "
|
||||
"UniffiAsyncCallHandler::FutureCallback"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
// Invalid poll code, this should never happen, but if it does log an
|
||||
// error and reject the promise.
|
||||
MOZ_LOG(gUniffiLogger, LogLevel::Error,
|
||||
("[UniFFI] Invalid poll code in "
|
||||
"UniffiAsyncCallHandler::FutureCallback %d",
|
||||
aCode));
|
||||
handler->mPromise->MaybeRejectWithUndefined();
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void UniffiAsyncCallHandler::Poll(UniquePtr<UniffiAsyncCallHandler> aHandler) {
|
||||
auto futureHandle = aHandler->mFutureHandle;
|
||||
auto pollFn = aHandler->mPollFn;
|
||||
// Release the UniquePtr into a raw pointer and convert it to a handle
|
||||
// so that we can pass it as a handle to the UniFFI code. It gets converted
|
||||
// back in `UniffiAsyncCallHandler::FutureCallback()`, which the Rust code
|
||||
// guarentees will be called if the future makes progress.
|
||||
uint64_t selfHandle =
|
||||
static_cast<uint64_t>(reinterpret_cast<uintptr_t>(aHandler.release()));
|
||||
pollFn(futureHandle, UniffiAsyncCallHandler::FutureCallback, selfHandle);
|
||||
}
|
||||
|
||||
// Complete the Rust future, extract the call result and resolve/reject the JS
|
||||
// promise
|
||||
void UniffiAsyncCallHandler::Finish(
|
||||
UniquePtr<UniffiAsyncCallHandler> aHandler) {
|
||||
RefPtr<dom::Promise> promise = aHandler->mPromise;
|
||||
if (!promise) {
|
||||
return;
|
||||
}
|
||||
dom::AutoEntryScript aes(promise->GetGlobalObject(),
|
||||
"UniffiAsyncCallHandler::Finish");
|
||||
dom::RootedDictionary<dom::UniFFIScaffoldingCallResult> returnValue(aes.cx());
|
||||
ErrorResult error;
|
||||
|
||||
RustCallStatus callStatus{};
|
||||
aHandler->CallCompleteFn(&callStatus);
|
||||
aHandler->mUniffiCallStatusCode = callStatus.code;
|
||||
if (callStatus.error_buf.data) {
|
||||
aHandler->mUniffiCallStatusErrorBuf = OwnedRustBuffer(callStatus.error_buf);
|
||||
}
|
||||
aHandler->ExtractCallResult(aes.cx(), returnValue, error);
|
||||
error.WouldReportJSException();
|
||||
if (error.Failed()) {
|
||||
aHandler->mPromise->MaybeReject(std::move(error));
|
||||
} else {
|
||||
aHandler->mPromise->MaybeResolve(returnValue);
|
||||
}
|
||||
}
|
||||
|
||||
UniffiAsyncCallHandler::~UniffiAsyncCallHandler() { mFreeFn(mFutureHandle); }
|
||||
|
||||
} // namespace mozilla::uniffi
|
||||
@@ -9,11 +9,9 @@
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/dom/OwnedRustBuffer.h"
|
||||
#include "mozilla/dom/UniFFIRust.h"
|
||||
#include "mozilla/dom/UniFFIScaffolding.h"
|
||||
#include "mozilla/uniffi/OwnedRustBuffer.h"
|
||||
#include "mozilla/uniffi/FfiValue.h"
|
||||
#include "mozilla/uniffi/ResultPromise.h"
|
||||
#include "mozilla/uniffi/Rust.h"
|
||||
|
||||
namespace mozilla::uniffi {
|
||||
|
||||
@@ -30,7 +28,7 @@ namespace mozilla::uniffi {
|
||||
// In all cases, a new instance is created each time the scaffolding function
|
||||
// is called.
|
||||
class UniffiCallHandlerBase {
|
||||
public:
|
||||
protected:
|
||||
// Extract the call result when the status code is `RUST_CALL_SUCCESS`.
|
||||
//
|
||||
// On success, set aDest with the converted return value. If there is a
|
||||
@@ -38,7 +36,7 @@ class UniffiCallHandlerBase {
|
||||
// value doesn't fit into a JS number.
|
||||
//
|
||||
// Called on the main thread.
|
||||
virtual void LiftSuccessfulCallResult(
|
||||
virtual void ExtractSuccessfulCallResult(
|
||||
JSContext* aCx, dom::Optional<dom::OwningUniFFIScaffoldingValue>& aDest,
|
||||
ErrorResult& aError) = 0;
|
||||
|
||||
@@ -54,17 +52,14 @@ class UniffiCallHandlerBase {
|
||||
// panic=abort.
|
||||
// - If some other error happens in the C++ layer, then `aError` will be set
|
||||
// to the error.
|
||||
void LiftCallResult(
|
||||
void ExtractCallResult(
|
||||
JSContext* aCx,
|
||||
dom::RootedDictionary<dom::UniFFIScaffoldingCallResult>& aDest,
|
||||
ErrorResult& aError);
|
||||
|
||||
virtual ~UniffiCallHandlerBase() = default;
|
||||
|
||||
protected:
|
||||
// Call status from the rust call
|
||||
int8_t mUniffiCallStatusCode = RUST_CALL_SUCCESS;
|
||||
FfiValueRustBuffer mUniffiCallStatusErrorBuf;
|
||||
OwnedRustBuffer mUniffiCallStatusErrorBuf;
|
||||
};
|
||||
|
||||
// Call scaffolding functions for synchronous Rust calls
|
||||
@@ -74,7 +69,7 @@ class UniffiSyncCallHandler : public UniffiCallHandlerBase {
|
||||
|
||||
// Convert a sequence of JS arguments and store them in this
|
||||
// UniffiSyncCallHandler. Called on the main thread.
|
||||
virtual void LowerRustArgs(
|
||||
virtual void PrepareRustArgs(
|
||||
const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs,
|
||||
ErrorResult& aError) = 0;
|
||||
|
||||
@@ -121,9 +116,9 @@ class UniffiAsyncCallHandler : public UniffiCallHandlerBase {
|
||||
//
|
||||
// Always called on the main thread since async Rust calls don't block, they
|
||||
// return a future. Because of this, there's no reason to split out the
|
||||
// `LowerRustArgs` and `MakeRustCall` like in the sync
|
||||
// `PrepareRustArgs` and `PrepareArgs` and `MakeRustCall` like in the sync
|
||||
// case.
|
||||
virtual void LowerArgsAndMakeRustCall(
|
||||
virtual void PrepareArgsAndMakeRustCall(
|
||||
const dom::Sequence<dom::OwningUniFFIScaffoldingValue>& aArgs,
|
||||
ErrorResult& aError) = 0;
|
||||
|
||||
@@ -145,6 +140,11 @@ class UniffiAsyncCallHandler : public UniffiCallHandlerBase {
|
||||
// Call mPollFn to poll the future
|
||||
static void Poll(UniquePtr<UniffiAsyncCallHandler> aHandler);
|
||||
|
||||
// Complete the async call and resolve the promise returned by CallAsync
|
||||
//
|
||||
// Called in the main thread.
|
||||
static void Finish(UniquePtr<UniffiAsyncCallHandler> aHandler);
|
||||
|
||||
public:
|
||||
virtual ~UniffiAsyncCallHandler();
|
||||
|
||||
@@ -159,7 +159,7 @@ class UniffiAsyncCallHandler : public UniffiCallHandlerBase {
|
||||
|
||||
private:
|
||||
// Promise created by CallAsync
|
||||
ResultPromise mPromise;
|
||||
RefPtr<dom::Promise> mPromise;
|
||||
|
||||
// Callback function for Rust async calls
|
||||
//
|
||||
@@ -7,10 +7,10 @@
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsString.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/uniffi/OwnedRustBuffer.h"
|
||||
#include "mozilla/dom/OwnedRustBuffer.h"
|
||||
#include "mozilla/dom/RootedDictionary.h"
|
||||
#include "mozilla/dom/UniFFIBinding.h"
|
||||
#include "mozilla/uniffi/Callbacks.h"
|
||||
#include "mozilla/dom/UniFFICallbacks.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/dom/UniFFIRust.h"
|
||||
#include "mozilla/dom/UniFFIScaffolding.h"
|
||||
#include "mozilla/uniffi/Rust.h"
|
||||
|
||||
namespace mozilla::uniffi {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,10 +7,10 @@
|
||||
#include "nsPrintfCString.h"
|
||||
#include "js/GCAPI.h"
|
||||
#include "mozilla/EndianUtils.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/dom/UniFFIBinding.h"
|
||||
#include "mozilla/dom/UniFFIPointer.h"
|
||||
#include "mozilla/uniffi/Rust.h"
|
||||
#include "mozilla/dom/UniFFIBinding.h"
|
||||
#include "mozilla/Logging.h"
|
||||
#include "UniFFIRust.h"
|
||||
|
||||
namespace mozilla::uniffi {
|
||||
extern mozilla::LazyLogModule gUniffiLogger;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "nsString.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "mozilla/uniffi/PointerType.h"
|
||||
#include "mozilla/dom/UniFFIPointerType.h"
|
||||
|
||||
namespace mozilla::dom {
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "nsISupports.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsLiteralString.h"
|
||||
#include "mozilla/uniffi/Rust.h"
|
||||
#include "UniFFIRust.h"
|
||||
|
||||
namespace mozilla::uniffi {
|
||||
|
||||
@@ -12,14 +12,14 @@
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/UniFFICall.h"
|
||||
#include "mozilla/dom/UniFFICallbacks.h"
|
||||
#include "mozilla/dom/UniFFIScaffolding.h"
|
||||
#include "mozilla/uniffi/Call.h"
|
||||
#include "mozilla/uniffi/Callbacks.h"
|
||||
|
||||
// This file implements the UniFFI WebIDL interface by leveraging the generate
|
||||
// code in UniFFIScaffolding.cpp. It's main purpose is to check if
|
||||
// MOZ_UNIFFI_FIXTURES is set and only try calling the scaffolding code if it
|
||||
// is.
|
||||
// code in UniFFIScaffolding.cpp and UniFFIFixtureScaffolding.cpp. It's main
|
||||
// purpose is to check if MOZ_UNIFFI_FIXTURES is set and only try calling the
|
||||
// scaffolding code if it is.
|
||||
|
||||
using mozilla::dom::ArrayBuffer;
|
||||
using mozilla::dom::GlobalObject;
|
||||
@@ -35,7 +35,7 @@ using mozilla::uniffi::UniffiSyncCallHandler;
|
||||
|
||||
namespace mozilla::uniffi {
|
||||
mozilla::LazyLogModule gUniffiLogger("uniffi");
|
||||
// Implemented in GeneratedScaffolding.cpp
|
||||
// Implemented in UniFFIGeneratedScaffolding.cpp
|
||||
UniquePtr<UniffiSyncCallHandler> GetSyncCallHandler(uint64_t aId);
|
||||
UniquePtr<UniffiAsyncCallHandler> GetAsyncCallHandler(uint64_t aId);
|
||||
Maybe<already_AddRefed<UniFFIPointer>> ReadPointer(
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
FINAL_LIBRARY = "xul"
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
"Call.cpp",
|
||||
"Callbacks.cpp",
|
||||
"GeneratedScaffolding.cpp",
|
||||
"OwnedRustBuffer.cpp",
|
||||
"ResultPromise.cpp",
|
||||
"UniFFICall.cpp",
|
||||
"UniFFICallbacks.cpp",
|
||||
"UniFFIGeneratedScaffolding.cpp",
|
||||
"UniFFIPointer.cpp",
|
||||
"UniFFIScaffolding.cpp",
|
||||
]
|
||||
@@ -20,18 +19,14 @@ if CONFIG["MOZ_UNIFFI_FIXTURES"]:
|
||||
DEFINES["MOZ_UNIFFI_FIXTURES"] = True
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
"UniFFIPointer.h",
|
||||
"UniFFIScaffolding.h",
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.uniffi += [
|
||||
"Call.h",
|
||||
"Callbacks.h",
|
||||
"FfiValue.h",
|
||||
"OwnedRustBuffer.h",
|
||||
"PointerType.h",
|
||||
"ResultPromise.h",
|
||||
"Rust.h",
|
||||
"ScaffoldingConverter.h",
|
||||
"UniFFICall.h",
|
||||
"UniFFICallbacks.h",
|
||||
"UniFFIPointer.h",
|
||||
"UniFFIPointerType.h",
|
||||
"UniFFIRust.h",
|
||||
"UniFFIScaffolding.h",
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
|
||||
@@ -215,7 +215,8 @@ toolkit/components/nimbus/schemas/ExperimentFeatureManifest.schema.json
|
||||
toolkit/components/nimbus/schemas/NimbusExperiment.schema.json
|
||||
toolkit/components/pdfjs/PdfJsDefaultPrefs.js
|
||||
toolkit/components/pdfjs/PdfJsOverridePrefs.js
|
||||
toolkit/components/uniffi-js/GeneratedScaffolding.cpp
|
||||
toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp
|
||||
toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp
|
||||
toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated
|
||||
tools/@types/tspaths.json
|
||||
tools/browsertime/package.json
|
||||
|
||||
Reference in New Issue
Block a user