diff --git a/.clang-format-ignore b/.clang-format-ignore index d6e5e9d0c769..315877cf66c3 100644 --- a/.clang-format-ignore +++ b/.clang-format-ignore @@ -63,6 +63,12 @@ widget/gtk/MPRISInterfaceDescription.h xpcom/reflect/xptcall/md/win32/.* 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/UniFFIGeneratedScaffolding.cpp +toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp + # Generated from ./tools/rewriting/ThirdPartyPaths.txt # awk '{print ""$1".*"}' ./tools/rewriting/ThirdPartyPaths.txt browser/components/translation/cld2/.* diff --git a/.eslintignore b/.eslintignore index 0cc0e1b0f0a7..abb5c8559fc1 100644 --- a/.eslintignore +++ b/.eslintignore @@ -228,3 +228,6 @@ toolkit/components/backgroundtasks/defaults # Ignore pre-generated webpack and typescript transpiled files for translations browser/extensions/translations/extension/ + +# "scaffolding" used by uniffi which isn't valid JS in its original form. +toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/ diff --git a/Cargo.toml b/Cargo.toml index 767120d7198d..6a0e0fcc2f1b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "security/manager/ssl/ipcclientcerts", "security/manager/ssl/osclientcerts", "testing/geckodriver", + "toolkit/components/uniffi-bindgen-gecko-js", "toolkit/crashreporter/rust_minidump_writer_linux", "toolkit/crashreporter/mozwer-rust", "toolkit/library/gtest/rust", diff --git a/dom/chrome-webidl/UniFFI.webidl b/dom/chrome-webidl/UniFFI.webidl new file mode 100644 index 000000000000..7840dd6af136 --- /dev/null +++ b/dom/chrome-webidl/UniFFI.webidl @@ -0,0 +1,59 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +// Interface for making UniFFI scaffolding calls +// +// Gecko uses UniFFI to generate privileged JS bindings for Rust components. +// UniFFI defines a C-ABI FFI layer for calling into Rust, called the +// scaffolding. This interface is a bridge that allows the JS code to make +// scaffolding calls +// +// See https://mozilla.github.io/uniffi-rs/ for details. + +// Opaque type used to represent a pointer from Rust +[ChromeOnly, Exposed=Window] +interface UniFFIPointer {}; + +// Types that can be passed or returned from scaffolding functions +// +// - double is used for all numeric types (including bool, which the JS code +// coerces to an int) +// - ArrayBuffer is used for RustBuffer +// - UniFFIPointer is used for Arc pointers +typedef (double or ArrayBuffer or UniFFIPointer) UniFFIScaffoldingType; + +// The result of a call into UniFFI scaffolding call +enum UniFFIScaffoldingCallCode { + "success", // Successful return + "error", // Rust Err return + "internal-error", // Internal/unexpected error +}; + +dictionary UniFFIScaffoldingCallResult { + required UniFFIScaffoldingCallCode code; + // For success, this will be the return value for non-void returns + // For error, this will be an ArrayBuffer storing the serialized error value + UniFFIScaffoldingType data; + // For internal-error, this will be a utf-8 string describing the error + ByteString internalErrorMessage; +}; + +// Functions to facilitate UniFFI scaffolding calls +// +// These should only be called by the generated code from UniFFI. +[ChromeOnly, Exposed=Window] +namespace UniFFIScaffolding { + [Throws] + Promise callAsync(unsigned long long id, UniFFIScaffoldingType... args); + + [Throws] + UniFFIScaffoldingCallResult callSync(unsigned long long id, UniFFIScaffoldingType... args); + + [Throws] + UniFFIPointer readPointer(unsigned long long id, ArrayBuffer buff, long position); + + [Throws] + void writePointer(unsigned long long id, UniFFIPointer ptr, ArrayBuffer buff, long position); +}; diff --git a/dom/chrome-webidl/moz.build b/dom/chrome-webidl/moz.build index 1cc38b585b09..f96396ecd3a7 100644 --- a/dom/chrome-webidl/moz.build +++ b/dom/chrome-webidl/moz.build @@ -81,6 +81,7 @@ WEBIDL_FILES = [ "SessionStoreUtils.webidl", "StructuredCloneHolder.webidl", "TelemetryStopwatch.webidl", + "UniFFI.webidl", "UserInteraction.webidl", "WebExtensionContentScript.webidl", "WebExtensionPolicy.webidl", diff --git a/toolkit/components/moz.build b/toolkit/components/moz.build index 438a1067169c..1c23f8672a80 100644 --- a/toolkit/components/moz.build +++ b/toolkit/components/moz.build @@ -75,6 +75,7 @@ DIRS += [ "timermanager", "tooltiptext", "typeaheadfind", + "uniffi-js", "utils", "url-classifier", "urlformatter", diff --git a/toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml b/toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml new file mode 100644 index 000000000000..a1320865b7ac --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "uniffi-bindgen-gecko-js" +version = "0.1.0" +edition = "2018" + +[[bin]] +name = "uniffi-bindgen-gecko-js" +path = "src/main.rs" + +[dependencies] +anyhow = "1" +askama = { version = "0.11", default-features = false, features = ["config"] } +clap = { version = "3.1", features = ["std", "derive"] } +extend = "1.1" +heck = "0.4" +uniffi_bindgen = "0.18" +serde = "1" +toml = "0.5" +camino = "1.0.8" diff --git a/toolkit/components/uniffi-bindgen-gecko-js/askama.toml b/toolkit/components/uniffi-bindgen-gecko-js/askama.toml new file mode 100644 index 000000000000..066e3c468ce1 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/askama.toml @@ -0,0 +1,2 @@ +[general] +dirs = ["src/templates"] diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/ci_list.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/ci_list.rs new file mode 100644 index 000000000000..46750979147b --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/ci_list.rs @@ -0,0 +1,139 @@ +/* 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/. */ + +//! Manage the universe of ComponentInterfaces +//! +//! uniffi-bindgen-gecko-js is unique because it generates bindings over a set of UDL files rather +//! than just one. This is because we want to generate the WebIDL statically rather than generate +//! it. To accomplish that, each WebIDL function inputs an opaque integer id that identifies which +//! version of it should run, for example `CallSync` inputs a function id. Operating on all UDL +//! files at once simplifies the task of ensuring those ids are to be unique and consistent between +//! the JS and c++ code. +//! +//! This module manages the list of ComponentInterface and the object ids. + +use crate::render::cpp::ComponentInterfaceCppExt; +use anyhow::{bail, Context, Result}; +use camino::Utf8PathBuf; +use std::collections::{BTreeSet, HashMap, HashSet}; +use uniffi_bindgen::interface::{ComponentInterface, FFIFunction, Object}; + +pub struct ComponentInterfaceUniverse { + ci_list: Vec, + fixture_ci_list: Vec, +} + +impl ComponentInterfaceUniverse { + pub fn new(udl_files: Vec, fixture_udl_files: Vec) -> Result { + let ci_list = udl_files + .into_iter() + .map(parse_udl_file) + .collect::>>()?; + let fixture_ci_list = fixture_udl_files + .into_iter() + .map(parse_udl_file) + .collect::>>()?; + Self::check_udl_namespaces_unique(&ci_list, &fixture_ci_list)?; + Ok(Self { + ci_list, + fixture_ci_list, + }) + } + + fn check_udl_namespaces_unique( + ci_list: &Vec, + fixture_ci_list: &Vec, + ) -> Result<()> { + let mut set = HashSet::new(); + for ci in ci_list.iter().chain(fixture_ci_list.iter()) { + if !set.insert(ci.namespace()) { + bail!("UDL files have duplicate namespace: {}", ci.namespace()); + } + } + Ok(()) + } + + pub fn ci_list(&self) -> &Vec { + &self.ci_list + } + + pub fn fixture_ci_list(&self) -> &Vec { + &self.fixture_ci_list + } + + pub fn iter_all(&self) -> impl Iterator { + self.ci_list.iter().chain(self.fixture_ci_list.iter()) + } +} + +fn parse_udl_file(udl_file: Utf8PathBuf) -> Result { + let udl = std::fs::read_to_string(&udl_file).context("Error reading UDL file")?; + ComponentInterface::from_webidl(&udl).context("Failed to parse UDL") +} + +pub struct FunctionIds<'a> { + // Map (CI namespace, func name) -> Ids + map: HashMap<(&'a str, &'a str), usize>, +} + +impl<'a> FunctionIds<'a> { + pub fn new(cis: &'a ComponentInterfaceUniverse) -> Self { + Self { + map: cis + .iter_all() + .flat_map(|ci| { + ci.exposed_functions() + .into_iter() + .map(move |f| (ci.namespace(), f.name())) + }) + .enumerate() + .map(|(i, (namespace, name))| ((namespace, name), i)) + // Sort using BTreeSet to guarantee the IDs remain stable across runs + .collect::>() + .into_iter() + .collect(), + } + } + + pub fn get(&self, ci: &ComponentInterface, func: &FFIFunction) -> usize { + return *self.map.get(&(ci.namespace(), func.name())).unwrap(); + } + + pub fn name(&self, ci: &ComponentInterface, func: &FFIFunction) -> String { + format!("{}:{}", ci.namespace(), func.name()) + } +} + +pub struct ObjectIds<'a> { + // Map (CI namespace, object name) -> Ids + map: HashMap<(&'a str, &'a str), usize>, +} + +impl<'a> ObjectIds<'a> { + pub fn new(cis: &'a ComponentInterfaceUniverse) -> Self { + Self { + map: cis + .iter_all() + .flat_map(|ci| { + ci.object_definitions() + .iter() + .map(move |o| (ci.namespace(), o.name())) + }) + .enumerate() + .map(|(i, (namespace, name))| ((namespace, name), i)) + // Sort using BTreeSet to guarantee the IDs remain stable across runs + .collect::>() + .into_iter() + .collect(), + } + } + + pub fn get(&self, ci: &ComponentInterface, obj: &Object) -> usize { + return *self.map.get(&(ci.namespace(), obj.name())).unwrap(); + } + + pub fn name(&self, ci: &ComponentInterface, obj: &Object) -> String { + format!("{}:{}", ci.namespace(), obj.name()) + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/lib.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/lib.rs new file mode 100644 index 000000000000..1a06e77fee04 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/lib.rs @@ -0,0 +1,123 @@ +/* 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/. */ + +use anyhow::{Context, Result}; +use askama::Template; +use camino::Utf8PathBuf; +use clap::Parser; +use heck::ToTitleCase; +use std::fs::File; +use std::io::Write; + +mod ci_list; +mod render; + +pub use ci_list::{ComponentInterfaceUniverse, FunctionIds, ObjectIds}; +pub use render::cpp::CPPScaffoldingTemplate; +pub use render::js::JSBindingsTemplate; +use uniffi_bindgen::ComponentInterface; + +#[derive(Debug, Parser)] +#[clap(name = "uniffi-bindgen-gecko-js")] +#[clap(version = clap::crate_version!())] +#[clap(about = "JS bindings generator for Rust")] +#[clap(propagate_version = true)] +struct CliArgs { + // This is a really convoluted set of arguments, but we're only expecting to be called by + // `mach_commands.py` + #[clap(long, value_name = "FILE")] + js_dir: Utf8PathBuf, + + #[clap(long, value_name = "FILE")] + fixture_js_dir: Utf8PathBuf, + + #[clap(long, value_name = "FILE")] + cpp_path: Utf8PathBuf, + + #[clap(long, value_name = "FILE")] + fixture_cpp_path: Utf8PathBuf, + + #[clap(long, multiple_values = true, value_name = "FILES")] + udl_files: Vec, + + #[clap(long, multiple_values = true, value_name = "FILES")] + fixture_udl_files: Vec, +} + +fn render(out_path: Utf8PathBuf, template: impl Template) -> Result<()> { + println!("rendering {}", out_path); + let contents = template.render()?; + let mut f = + File::create(&out_path).context(format!("Failed to create {:?}", out_path.file_name()))?; + write!(f, "{}\n", contents).context(format!("Failed to write to {}", out_path)) +} + +fn render_cpp( + path: Utf8PathBuf, + prefix: &str, + ci_list: &Vec, + function_ids: &FunctionIds, + object_ids: &ObjectIds, +) -> Result<()> { + render( + path, + CPPScaffoldingTemplate { + prefix, + ci_list, + function_ids: &function_ids, + object_ids: &object_ids, + }, + ) +} + +fn render_js( + out_dir: Utf8PathBuf, + ci_list: &Vec, + function_ids: &FunctionIds, + object_ids: &ObjectIds, +) -> Result<()> { + for ci in ci_list { + let path = out_dir.join(format!("{}.jsm", ci.namespace().to_title_case())); + render( + path, + JSBindingsTemplate { + ci, + function_ids: &function_ids, + object_ids: &object_ids, + }, + )?; + } + Ok(()) +} + +pub fn run_main() -> Result<()> { + let args = CliArgs::parse(); + let cis = ComponentInterfaceUniverse::new(args.udl_files, args.fixture_udl_files)?; + let function_ids = FunctionIds::new(&cis); + let object_ids = ObjectIds::new(&cis); + + render_cpp( + args.cpp_path, + "UniFFI", + cis.ci_list(), + &function_ids, + &object_ids, + )?; + render_cpp( + args.fixture_cpp_path, + "UniFFIFixtures", + cis.fixture_ci_list(), + &function_ids, + &object_ids, + )?; + render_js(args.js_dir, cis.ci_list(), &function_ids, &object_ids)?; + render_js( + args.fixture_js_dir, + cis.fixture_ci_list(), + &function_ids, + &object_ids, + )?; + + Ok(()) +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/main.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/main.rs new file mode 100644 index 000000000000..eefe72ba662f --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/main.rs @@ -0,0 +1,9 @@ +/* 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/. */ + +use anyhow::Result; + +fn main() -> Result<()> { + uniffi_bindgen_gecko_js::run_main() +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs new file mode 100644 index 000000000000..b99fcf344f65 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs @@ -0,0 +1,154 @@ +/* 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/. */ + +use crate::{FunctionIds, ObjectIds}; +use askama::Template; +use extend::ext; +use heck::ToUpperCamelCase; +use std::collections::HashSet; +use std::iter; +use uniffi_bindgen::interface::{ComponentInterface, FFIArgument, FFIFunction, FFIType, Object}; + +#[derive(Template)] +#[template(path = "UniFFIScaffolding.cpp", escape = "none")] +pub struct CPPScaffoldingTemplate<'a> { + // Prefix for each function name in. This is related to how we handle the test fixtures. For + // each function defined in the UniFFI namespace in UniFFI.webidl we: + // - Generate a function in to handle it using the real UDL files + // - Generate a different function in for handle it using the fixture UDL files + // - Have a hand-written stub function that always calls the first function and only calls + // the second function in if MOZ_UNIFFI_FIXTURES is defined. + pub prefix: &'a str, + pub ci_list: &'a Vec, + pub function_ids: &'a FunctionIds<'a>, + pub object_ids: &'a ObjectIds<'a>, +} + +// Define extension traits with methods used in our template code + +#[ext(name=ComponentInterfaceCppExt)] +pub impl ComponentInterface { + // C++ pointer type name. This needs to be a valid C++ type name and unique across all UDL + // files. + fn pointer_type(&self, object: &Object) -> String { + self._pointer_type(object.name()) + } + + fn _pointer_type(&self, name: &str) -> String { + format!( + "k{}{}PointerType", + self.namespace().to_upper_camel_case(), + name.to_upper_camel_case() + ) + } + + // Iterate over all functions to expose via the UniFFIScaffolding class + // + // This is basically all the user functions, except we don't expose the free methods for + // objects. Freeing is handled by the UniFFIPointer class. + // + // Note: this function should return `impl Iterator<&FFIFunction>`, but that's not currently + // allowed for traits. + fn exposed_functions(&self) -> Vec<&FFIFunction> { + let excluded: HashSet<_> = self + .object_definitions() + .iter() + .map(|o| o.ffi_object_free().name()) + .collect(); + self.iter_user_ffi_function_definitions() + .filter(move |f| !excluded.contains(f.name())) + .collect() + } + + // ScaffoldingConverter class + // + // This is used to convert types between the JS code and Rust + fn scaffolding_converter(&self, ffi_type: &FFIType) -> String { + match ffi_type { + FFIType::RustArcPtr(name) => { + format!("ScaffoldingObjectConverter<&{}>", self._pointer_type(name),) + } + _ => format!("ScaffoldingConverter<{}>", ffi_type.rust_type()), + } + } + + // ScaffoldingCallHandler class + fn scaffolding_call_handler(&self, func: &FFIFunction) -> String { + let return_param = match func.return_type() { + Some(return_type) => self.scaffolding_converter(return_type), + None => "ScaffoldingConverter".to_string(), + }; + let all_params = iter::once(return_param) + .chain( + func.arguments() + .into_iter() + .map(|a| self.scaffolding_converter(&a.type_())), + ) + .collect::>() + .join(", "); + return format!("ScaffoldingCallHandler<{}>", all_params); + } +} + +#[ext(name=FFIFunctionCppExt)] +pub impl FFIFunction { + fn nm(&self) -> String { + self.name().to_upper_camel_case() + } + + fn rust_name(&self) -> String { + self.name().to_string() + } + + fn rust_return_type(&self) -> String { + match self.return_type() { + Some(t) => t.rust_type(), + None => "void".to_owned(), + } + } + + fn rust_arg_list(&self) -> String { + let mut parts: Vec = self.arguments().iter().map(|a| a.rust_type()).collect(); + parts.push("RustCallStatus*".to_owned()); + parts.join(", ") + } +} + +#[ext(name=FFITypeCppExt)] +pub impl FFIType { + // Type for the Rust scaffolding code + fn rust_type(&self) -> String { + match self { + FFIType::UInt8 => "uint8_t", + FFIType::Int8 => "int8_t", + FFIType::UInt16 => "uint16_t", + FFIType::Int16 => "int16_t", + FFIType::UInt32 => "uint32_t", + FFIType::Int32 => "int32_t", + FFIType::UInt64 => "uint64_t", + FFIType::Int64 => "int64_t", + FFIType::Float32 => "float", + FFIType::Float64 => "double", + FFIType::RustBuffer => "RustBuffer", + FFIType::RustArcPtr(_) => "void *", + FFIType::ForeignBytes => unimplemented!("ForeignBytes not supported"), + FFIType::ForeignCallback => unimplemented!("ForeignCallback not supported"), + } + .to_owned() + } +} + +#[ext(name=FFIArgumentCppExt)] +pub impl FFIArgument { + fn rust_type(&self) -> String { + self.type_().rust_type() + } +} + +#[ext(name=ObjectCppExt)] +pub impl Object { + fn nm(&self) -> String { + self.name().to_upper_camel_case() + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs new file mode 100644 index 000000000000..5a42bafbf419 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs @@ -0,0 +1,232 @@ +/* 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/. */ + +use super::shared::*; +use crate::{FunctionIds, ObjectIds}; +use askama::Template; +use extend::ext; +use heck::{ToLowerCamelCase, ToShoutySnakeCase, ToUpperCamelCase}; +use uniffi_bindgen::interface::{ + Argument, ComponentInterface, Constructor, Enum, Error, Field, Function, Literal, Method, + Object, Radix, Record, Type, +}; + +fn arg_names(args: &[&Argument]) -> String { + args.iter() + .map(|arg| { + if let Some(default_value) = arg.default_value() { + format!("{} = {}", arg.nm(), default_value.render()) + } else { + arg.nm() + } + }) + .collect::>() + .join(",") +} + +fn render_enum_literal(typ: &Type, variant_name: &str) -> String { + if let Type::Enum(enum_name) = typ { + // TODO: This does not support complex enum literals yet. + return format!( + "{}.{}", + enum_name.to_upper_camel_case(), + variant_name.to_shouty_snake_case() + ); + } else { + panic!("Rendering an enum literal on a type that is not an enum") + } +} +#[derive(Template)] +#[template(path = "js/wrapper.jsm", escape = "none")] +pub struct JSBindingsTemplate<'a> { + pub ci: &'a ComponentInterface, + pub function_ids: &'a FunctionIds<'a>, + pub object_ids: &'a ObjectIds<'a>, +} + +// Define extension traits with methods used in our template code + +#[ext(name=LiteralJSExt)] +pub impl Literal { + fn render(&self) -> String { + match self { + Literal::Boolean(inner) => inner.to_string(), + Literal::String(inner) => format!("\"{}\"", inner), + Literal::UInt(num, radix, _) => format!("{}", radix.render_num(num)), + Literal::Int(num, radix, _) => format!("{}", radix.render_num(num)), + Literal::Float(num, _) => num.clone(), + Literal::Enum(name, typ) => render_enum_literal(typ, name), + Literal::EmptyMap => "{}".to_string(), + Literal::EmptySequence => "[]".to_string(), + Literal::Null => "null".to_string(), + } + } +} + +#[ext(name=RadixJSExt)] +pub impl Radix { + fn render_num( + &self, + num: impl std::fmt::Display + std::fmt::LowerHex + std::fmt::Octal, + ) -> String { + match self { + Radix::Decimal => format!("{}", num), + Radix::Hexadecimal => format!("{:#x}", num), + Radix::Octal => format!("{:#o}", num), + } + } +} + +#[ext(name=RecordJSExt)] +pub impl Record { + fn nm(&self) -> String { + self.name().to_upper_camel_case() + } + + fn constructor_field_list(&self) -> String { + self.fields() + .iter() + .map(|field| { + if let Some(default_value) = field.default_value() { + format!("{} = {}", field.nm(), default_value.render()) + } else { + field.nm() + } + }) + .collect::>() + .join(",") + } +} + +#[ext(name=FieldJSExt)] +pub impl Field { + fn nm(&self) -> String { + self.name().to_lower_camel_case() + } + + fn write_datastream_fn(&self) -> String { + self.type_().write_datastream_fn() + } + + fn read_datastream_fn(&self) -> String { + self.type_().read_datastream_fn() + } + + fn ffi_converter(&self) -> String { + self.type_().ffi_converter() + } + + fn check_type(&self) -> String { + format!( + "{}.checkType(\"{}\", {})", + self.type_().ffi_converter(), + self.nm(), + self.nm() + ) + } +} + +#[ext(name=ArgumentJSExt)] +pub impl Argument { + fn lower_fn_name(&self) -> String { + format!("{}.lower", self.type_().ffi_converter()) + } + + fn nm(&self) -> String { + self.name().to_lower_camel_case() + } + + fn check_type(&self) -> String { + format!( + "{}.checkType(\"{}\", {})", + self.type_().ffi_converter(), + self.nm(), + self.nm() + ) + } +} + +#[ext(name=TypeJSExt)] +pub impl Type { + // Render an expression to check if two instances of this type are equal + fn equals(&self, first: &str, second: &str) -> String { + match self { + Type::Record(_) => format!("{}.equals({})", first, second), + _ => format!("{} == {}", first, second), + } + } + + fn write_datastream_fn(&self) -> String { + format!("{}.write", self.ffi_converter()) + } + + fn read_datastream_fn(&self) -> String { + format!("{}.read", self.ffi_converter()) + } + + fn ffi_converter(&self) -> String { + format!( + "FfiConverter{}", + self.canonical_name().to_upper_camel_case() + ) + } +} + +#[ext(name=EnumJSExt)] +pub impl Enum { + fn nm(&self) -> String { + self.name().to_upper_camel_case() + } +} + +#[ext(name=FunctionJSExt)] +pub impl Function { + fn arg_names(&self) -> String { + arg_names(self.arguments().as_slice()) + } + + fn nm(&self) -> String { + self.name().to_lower_camel_case() + } +} + +#[ext(name=ErrorJSExt)] +pub impl Error { + fn nm(&self) -> String { + self.name().to_upper_camel_case() + } +} + +#[ext(name=ObjectJSExt)] +pub impl Object { + fn nm(&self) -> String { + self.name().to_upper_camel_case() + } +} + +#[ext(name=ConstructorJSExt)] +pub impl Constructor { + fn nm(&self) -> String { + if self.is_primary_constructor() { + "init".to_string() + } else { + self.name().to_lower_camel_case() + } + } + + fn arg_names(&self) -> String { + arg_names(&self.arguments().as_slice()) + } +} + +#[ext(name=MethodJSExt)] +pub impl Method { + fn arg_names(&self) -> String { + arg_names(self.arguments().as_slice()) + } + + fn nm(&self) -> String { + self.name().to_lower_camel_case() + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/render/mod.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/render/mod.rs new file mode 100644 index 000000000000..f9ceeb9872b9 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/mod.rs @@ -0,0 +1,7 @@ +/* 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/. */ + +pub mod cpp; +pub mod js; +pub mod shared; diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/render/shared.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/render/shared.rs new file mode 100644 index 000000000000..3f1631762531 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/shared.rs @@ -0,0 +1,39 @@ +/* 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/. */ + +/// Extension traits that are shared across multiple render targets +use extend::ext; +use uniffi_bindgen::interface::{Constructor, FFIFunction, Function, Method}; + +#[ext] +pub impl FFIFunction { + fn is_async(&self) -> bool { + // TODO check `uniffi.toml` or some other configuration to figure this out + true + } +} + +#[ext] +pub impl Function { + fn is_async(&self) -> bool { + // TODO check `uniffi.toml` or some other configuration to figure this out + true + } +} + +#[ext] +pub impl Constructor { + fn is_async(&self) -> bool { + // TODO check `uniffi.toml` or some other configuration to figure this out + true + } +} + +#[ext] +pub impl Method { + fn is_async(&self) -> bool { + // TODO check `uniffi.toml` or some other configuration to figure this out + true + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp new file mode 100644 index 000000000000..862564c261bb --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp @@ -0,0 +1,105 @@ +// Generated by uniffi-bindgen-gecko-js. DO NOT EDIT. + +#include "nsString.h" +#include "nsPrintfCString.h" +#include "mozilla/Maybe.h" +#include "mozilla/dom/UniFFIScaffolding.h" +#include "mozilla/dom/ScaffoldingCall.h" + +namespace mozilla::uniffi { + +using dom::ArrayBuffer; +using dom::GlobalObject; +using dom::RootedDictionary; +using dom::Promise; +using dom::ScaffoldingType; +using dom::Sequence; +using dom::UniFFIPointer; +using dom::UniFFIScaffoldingCallResult; + +// Define scaffolding functions from UniFFI +extern "C" { + {%- for ci in ci_list %} + {%- for func in ci.iter_user_ffi_function_definitions() %} + {{ func.rust_return_type() }} {{ func.rust_name() }}({{ func.rust_arg_list() }}); + {%- endfor %} + {%- endfor %} +} + +// Define pointer types +{%- for ci in ci_list %} +{%- for object in ci.object_definitions() %} +{%- let pointer_type = ci.pointer_type(object) %} +const static mozilla::uniffi::UniFFIPointerType {{ pointer_type }} { + "{{ "{}::{}"|format(ci.namespace(), object.name()) }}"_ns, + {{ object.ffi_object_free().rust_name() }} +}; + +{%- endfor %} +{%- endfor %} + +Maybe> {{ prefix }}CallAsync(const GlobalObject& aGlobal, uint64_t aId, const Sequence& aArgs, ErrorResult& aError) { + switch (aId) { + {%- for ci in ci_list %} + {%- for func in ci.exposed_functions() %} + case {{ function_ids.get(ci, func) }}: { // {{ function_ids.name(ci, func) }} + using CallHandler = {{ ci.scaffolding_call_handler(func) }}; + return Some(CallHandler::CallAsync({{ func.rust_name() }}, aGlobal, aArgs, "{{ func.name() }}: "_ns, aError)); + } + {%- endfor %} + {%- endfor %} + } + return Nothing(); +} + +bool {{ prefix }}CallSync(const GlobalObject& aGlobal, uint64_t aId, const Sequence& aArgs, RootedDictionary& aReturnValue, ErrorResult& aError) { + switch (aId) { + {%- for ci in ci_list %} + {%- for func in ci.exposed_functions() %} + case {{ function_ids.get(ci, func) }}: { // {{ function_ids.name(ci, func) }} + using CallHandler = {{ ci.scaffolding_call_handler(func) }}; + CallHandler::CallSync({{ func.rust_name() }}, aGlobal, aArgs, aReturnValue, "{{ func.name() }}: "_ns, aError); + return true; + } + {%- endfor %} + {%- endfor %} + } + return false; +} + +Maybe> {{ prefix }}ReadPointer(const GlobalObject& aGlobal, uint64_t aId, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) { + const UniFFIPointerType* type; + switch (aId) { + {%- for ci in ci_list %} + {%- for object in ci.object_definitions() %} + case {{ object_ids.get(ci, object) }}: { // {{ object_ids.name(ci, object) }} + type = &{{ ci.pointer_type(object) }}; + break; + } + {%- endfor %} + {%- endfor %} + default: + return Nothing(); + } + return Some(UniFFIPointer::Read(aArrayBuff, aPosition, type, aError)); +} + +bool {{ prefix }}WritePointer(const GlobalObject& aGlobal, uint64_t aId, const UniFFIPointer& aPtr, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) { + const UniFFIPointerType* type; + switch (aId) { + {%- for ci in ci_list %} + {%- for object in ci.object_definitions() %} + case {{ object_ids.get(ci, object) }}: { // {{ object_ids.name(ci, object) }} + type = &{{ ci.pointer_type(object) }}; + break; + } + {%- endfor %} + {%- endfor %} + default: + return false; + } + aPtr.Write(aArrayBuff, aPosition, type, aError); + return true; +} + +} // namespace mozilla::uniffi diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Boolean.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Boolean.jsm new file mode 100644 index 000000000000..0ba24e8c9076 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Boolean.jsm @@ -0,0 +1,21 @@ +class {{ ffi_converter }} extends FfiConverter { + static computeSize() { + return 1; + } + static lift(value) { + return value == 1; + } + static lower(value) { + if (value) { + return 1; + } else { + return 0; + } + } + static write(dataStream, value) { + dataStream.writeUint8(this.lower(value)) + } + static read(dataStream) { + return this.lift(dataStream.readUint8()) + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Enum.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Enum.jsm new file mode 100644 index 000000000000..69de63555b1d --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Enum.jsm @@ -0,0 +1,103 @@ +{%- let enum_ = ci.get_enum_definition(name).unwrap() %} + +{%- if enum_.is_flat() %} + +const {{ enum_.nm() }} = { + {%- for variant in enum_.variants() %} + {{ variant.name().to_shouty_snake_case() }}: {{loop.index}}, + {%- endfor %} +}; + +Object.freeze({{ enum_.nm() }}); +class {{ ffi_converter }} extends FfiConverterArrayBuffer { + static read(dataStream) { + switch (dataStream.readInt32()) { + {%- for variant in enum_.variants() %} + case {{ loop.index }}: + return {{ enum_.nm() }}.{{ variant.name().to_shouty_snake_case() }} + {%- endfor %} + default: + return new Error("Unknown {{ enum_.nm() }} variant"); + } + } + + static write(dataStream, value) { + {%- for variant in enum_.variants() %} + if (value === {{ enum_.nm() }}.{{ variant.name().to_shouty_snake_case() }}) { + dataStream.writeInt32({{ loop.index }}); + return; + } + {%- endfor %} + return new Error("Unknown {{ enum_.nm() }} variant"); + } + + static computeSize(value) { + return 4; + } +} + +{%- else %} + +class {{ enum_.nm() }} {} +{%- for variant in enum_.variants() %} +{{enum_.nm()}}.{{variant.name().to_upper_camel_case() }} = class extends {{ enum_.nm() }}{ + constructor( + {% for field in variant.fields() -%} + {{ field.nm() }}{%- if loop.last %}{%- else %}, {%- endif %} + {% endfor -%} + ) { + super(); + {%- for field in variant.fields() %} + this.{{field.nm()}} = {{ field.nm() }}; + {%- endfor %} + } +} +{%- endfor %} + +class {{ ffi_converter }} extends FfiConverterArrayBuffer { + static read(dataStream) { + switch (dataStream.readInt32()) { + {%- for variant in enum_.variants() %} + case {{ loop.index }}: + return new {{ enum_.nm() }}.{{ variant.name().to_upper_camel_case() }}( + {%- for field in variant.fields() %} + {{ field.ffi_converter() }}.read(dataStream){%- if loop.last %}{% else %}, {%- endif %} + {%- endfor %} + ); + {%- endfor %} + default: + return new Error("Unknown {{ enum_.nm() }} variant"); + } + } + + static write(dataStream, value) { + {%- for variant in enum_.variants() %} + if (value instanceof {{enum_.nm()}}.{{ variant.name().to_upper_camel_case() }}) { + dataStream.writeInt32({{ loop.index }}); + {%- for field in variant.fields() %} + {{ field.ffi_converter() }}.write(dataStream, value.{{ field.nm() }}); + {%- endfor %} + return; + } + {%- endfor %} + return new Error("Unknown {{ enum_.nm() }} variant"); + } + + static computeSize(value) { + // Size of the Int indicating the variant + let totalSize = 4; + {%- for variant in enum_.variants() %} + if (value instanceof {{enum_.nm()}}.{{ variant.name().to_upper_camel_case() }}) { + {%- for field in variant.fields() %} + totalSize += {{ field.ffi_converter() }}.computeSize(value.{{ field.nm() }}); + {%- endfor %} + return totalSize; + } + {%- endfor %} + return new Error("Unknown {{ enum_.nm() }} variant"); + } +} + +{%- endif %} + +EXPORTED_SYMBOLS.push("{{ enum_.nm() }}"); diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Error.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Error.jsm new file mode 100644 index 000000000000..ee20a885112e --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Error.jsm @@ -0,0 +1,51 @@ +{%- let error = ci.get_error_definition(name).unwrap() %} +{%- let string_type = Type::String %} +{%- let string_ffi_converter = string_type.ffi_converter() %} + +class {{ error.nm() }} extends Error {} +EXPORTED_SYMBOLS.push("{{ error.nm() }}"); + +{% for variant in error.variants() %} +class {{ variant.name().to_upper_camel_case() }} extends {{ error.nm() }} { + {% if error.is_flat() %} + constructor(message, ...params) { + super(...params); + this.message = message; + } + {%- else %} + constructor( + {% for field in variant.fields() -%} + {{field.nm()}}, + {% endfor -%} + ...params + ) { + super(...params); + {%- for field in variant.fields() %} + this.{{field.nm()}} = {{ field.nm() }}; + {%- endfor %} + } + {%- endif %} +} +EXPORTED_SYMBOLS.push("{{ variant.name().to_upper_camel_case() }}"); +{%-endfor %} + +class {{ ffi_converter }} extends FfiConverterArrayBuffer { + static read(dataStream) { + switch (dataStream.readInt32()) { + {%- for variant in error.variants() %} + case {{ loop.index }}: + {%- if error.is_flat() %} + return new {{ variant.name().to_upper_camel_case() }}({{ string_ffi_converter }}.read(dataStream)); + {%- else %} + return new {{ variant.name().to_upper_camel_case() }}( + {%- for field in variant.fields() %} + {{ field.ffi_converter() }}.read(dataStream){%- if loop.last %}{% else %}, {%- endif %} + {%- endfor %} + ); + {%- endif %} + {%- endfor %} + default: + return new Error("Unknown {{ error.nm() }} variant"); + } + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Float32.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Float32.jsm new file mode 100644 index 000000000000..be1ce942e74b --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Float32.jsm @@ -0,0 +1,17 @@ +class {{ ffi_converter }} extends FfiConverter { + static computeSize() { + return 4; + } + static lift(value) { + return value; + } + static lower(value) { + return value; + } + static write(dataStream, value) { + dataStream.writeFloat32(value) + } + static read(dataStream) { + return dataStream.readFloat32() + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Float64.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Float64.jsm new file mode 100644 index 000000000000..039634624a4c --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Float64.jsm @@ -0,0 +1,17 @@ +class {{ ffi_converter }} extends FfiConverter { + static computeSize() { + return 8; + } + static lift(value) { + return value; + } + static lower(value) { + return value; + } + static write(dataStream, value) { + dataStream.writeFloat64(value) + } + static read(dataStream) { + return dataStream.readFloat64() + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Helpers.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Helpers.jsm new file mode 100644 index 000000000000..70a15ef65f1a --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Helpers.jsm @@ -0,0 +1,229 @@ +// Write/Read data to/from an ArrayBuffer +class ArrayBufferDataStream { + constructor(arrayBuffer) { + this.dataView = new DataView(arrayBuffer); + this.pos = 0; + } + + readUint8() { + let rv = this.dataView.getUint8(this.pos); + this.pos += 1; + return rv; + } + + writeUint8(value) { + this.dataView.setUint8(this.pos, value); + this.pos += 1; + } + + readUint16() { + let rv = this.dataView.getUint16(this.pos); + this.pos += 2; + return rv; + } + + writeUint16(value) { + this.dataView.setUint16(this.pos, value); + this.pos += 2; + } + + readUint32() { + let rv = this.dataView.getUint32(this.pos); + this.pos += 4; + return rv; + } + + writeUint32(value) { + this.dataView.setUint32(this.pos, value); + this.pos += 4; + } + + readUint64() { + let rv = this.dataView.getBigUint64(this.pos); + this.pos += 8; + return Number(rv); + } + + writeUint64(value) { + this.dataView.setBigUint64(this.pos, BigInt(value)); + this.pos += 8; + } + + + readInt8() { + let rv = this.dataView.getInt8(this.pos); + this.pos += 1; + return rv; + } + + writeInt8(value) { + this.dataView.setInt8(this.pos, value); + this.pos += 1; + } + + readInt16() { + let rv = this.dataView.getInt16(this.pos); + this.pos += 2; + return rv; + } + + writeInt16(value) { + this.dataView.setInt16(this.pos, value); + this.pos += 2; + } + + readInt32() { + let rv = this.dataView.getInt32(this.pos); + this.pos += 4; + return rv; + } + + writeInt32(value) { + this.dataView.setInt32(this.pos, value); + this.pos += 4; + } + + readInt64() { + let rv = this.dataView.getBigInt64(this.pos); + this.pos += 8; + return Number(rv); + } + + writeInt64(value) { + this.dataView.setBigInt64(this.pos, BigInt(value)); + this.pos += 8; + } + + + readFloat32() { + let rv = this.dataView.getFloat32(this.pos); + this.pos += 4; + return rv; + } + + writeFloat32(value) { + this.dataView.setFloat32(this.pos, value); + this.pos += 4; + } + + readFloat64() { + let rv = this.dataView.getFloat64(this.pos); + this.pos += 8; + return rv; + } + + writeFloat64(value) { + this.dataView.setFloat64(this.pos, value); + this.pos += 8; + } + + + writeString(value) { + const encoder = new TextEncoder(); + // Note: in order to efficiently write this data, we first write the + // string data, reserving 4 bytes for the size. + const dest = new Uint8Array(this.dataView.buffer, this.pos + 4); + const encodeResult = encoder.encodeInto(value, dest); + if (encodeResult.read != value.length) { + throw new UniFFIError( + "writeString: out of space when writing to ArrayBuffer. Did the computeSize() method returned the wrong result?" + ); + } + const size = encodeResult.written; + // Next, go back and write the size before the string data + this.dataView.setUint32(this.pos, size); + // Finally, advance our position past both the size and string data + this.pos += size + 4; + } + + readString() { + const decoder = new TextDecoder(); + const size = this.readUint32(); + const source = new Uint8Array(this.dataView.buffer, this.pos, size) + const value = decoder.decode(source); + this.pos += size; + return value; + } + + {%- for object in ci.object_definitions() %} + + // Reads a {{ object.nm() }} pointer from the data stream + // UniFFI Pointers are **always** 8 bytes long. That is enforced + // by the C++ and Rust Scaffolding code. + readPointer{{ object.nm() }}() { + const pointerId = {{ object_ids.get(ci, object) }}; // {{ object_ids.name(ci, object) }} + const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos); + this.pos += 8; + return res; + } + + // Writes a {{ object.nm() }} pointer into the data stream + // UniFFI Pointers are **always** 8 bytes long. That is enforced + // by the C++ and Rust Scaffolding code. + writePointer{{ object.nm() }}(value) { + const pointerId = {{ object_ids.get(ci, object) }}; // {{ object_ids.name(ci, object) }} + UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos); + this.pos += 8; + } + {% endfor %} +} + +function handleRustResult(result, liftCallback, liftErrCallback) { + switch (result.code) { + case "success": + return liftCallback(result.data); + + case "error": + throw liftErrCallback(result.data); + + case "internal-error": + let message = result.internalErrorMessage; + if (message) { + throw new UniFFIInternalError(message); + } else { + throw new UniFFIInternalError("Unknown error"); + } + + default: + throw new UniFFIError(`Unexpected status code: ${result.code}`); + } +} + +class UniFFIError { + constructor(message) { + this.message = message; + } +} + +class UniFFIInternalError extends UniFFIError {} + +// Base class for FFI converters +class FfiConverter { + static checkType(name, value) { + if (value === undefined ) { + throw TypeError(`${name} is undefined`); + } + if (value === null ) { + throw TypeError(`${name} is null`); + } + } +} + +// Base class for FFI converters that lift/lower by reading/writing to an ArrayBuffer +class FfiConverterArrayBuffer extends FfiConverter { + static lift(buf) { + return this.read(new ArrayBufferDataStream(buf)); + } + + static lower(value) { + const buf = new ArrayBuffer(this.computeSize(value)); + const dataStream = new ArrayBufferDataStream(buf); + this.write(dataStream, value); + return buf; + } +} + +// Symbols that are used to ensure that Object constructors +// can only be used with a proper UniFFI pointer +const uniffiObjectPtr = Symbol("uniffiObjectPtr"); +const constructUniffiObject = Symbol("constructUniffiObject"); diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int16.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int16.jsm new file mode 100644 index 000000000000..d7195e2ec695 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int16.jsm @@ -0,0 +1,26 @@ +class {{ ffi_converter }} extends FfiConverter { + static checkType(name, value) { + super.checkType(name, value); + if (!Number.isInteger(value)) { + throw TypeError(`${name} is not an integer(${value})`); + } + if (value < -32768 || value > 32767) { + throw TypeError(`${name} exceeds the I16 bounds (${value})`); + } + } + static computeSize() { + return 2; + } + static lift(value) { + return value; + } + static lower(value) { + return value; + } + static write(dataStream, value) { + dataStream.writeInt16(value) + } + static read(dataStream) { + return dataStream.readInt16() + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int32.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int32.jsm new file mode 100644 index 000000000000..81c64343ebc6 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int32.jsm @@ -0,0 +1,26 @@ +class {{ ffi_converter }} extends FfiConverter { + static checkType(name, value) { + super.checkType(name, value); + if (!Number.isInteger(value)) { + throw TypeError(`${name} is not an integer(${value})`); + } + if (value < -2147483648 || value > 2147483647) { + throw TypeError(`${name} exceeds the I32 bounds (${value})`); + } + } + static computeSize() { + return 4; + } + static lift(value) { + return value; + } + static lower(value) { + return value; + } + static write(dataStream, value) { + dataStream.writeInt32(value) + } + static read(dataStream) { + return dataStream.readInt32() + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int64.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int64.jsm new file mode 100644 index 000000000000..7e62a4b40187 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int64.jsm @@ -0,0 +1,23 @@ +class {{ ffi_converter }} extends FfiConverter { + static checkType(name, value) { + super.checkType(name, value); + if (!Number.isSafeInteger(value)) { + throw TypeError(`${name} exceeds the safe integer bounds (${value})`); + } + } + static computeSize() { + return 8; + } + static lift(value) { + return value; + } + static lower(value) { + return value; + } + static write(dataStream, value) { + dataStream.writeInt64(value) + } + static read(dataStream) { + return dataStream.readInt64() + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int8.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int8.jsm new file mode 100644 index 000000000000..31e9b4c81159 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int8.jsm @@ -0,0 +1,26 @@ +class {{ ffi_converter }} extends FfiConverter { + static checkType(name, value) { + super.checkType(name, value); + if (!Number.isInteger(value)) { + throw TypeError(`${name} is not an integer(${value})`); + } + if (value < -128 || value > 127) { + throw TypeError(`${name} exceeds the I8 bounds (${value})`); + } + } + static computeSize() { + return 1; + } + static lift(value) { + return value; + } + static lower(value) { + return value; + } + static write(dataStream, value) { + dataStream.writeInt8(value) + } + static read(dataStream) { + return dataStream.readInt8() + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Map.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Map.jsm new file mode 100644 index 000000000000..9efa3dc556eb --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Map.jsm @@ -0,0 +1,32 @@ +class {{ ffi_converter }} extends FfiConverterArrayBuffer { + static read(dataStream) { + const len = dataStream.readInt32(); + const map = {}; + for (let i = 0; i < len; i++) { + const key = {{ key_type.ffi_converter() }}.read(dataStream); + const value = {{ value_type.ffi_converter() }}.read(dataStream); + map[key] = value; + } + + return map; + } + + static write(dataStream, value) { + dataStream.writeInt32(Object.keys(value).length); + for (const key in value) { + {{ key_type.ffi_converter() }}.write(dataStream, key); + {{ value_type.ffi_converter() }}.write(dataStream, value[key]); + } + } + + static computeSize(value) { + // The size of the length + let size = 4; + for (const key in value) { + size += {{ key_type.ffi_converter() }}.computeSize(key); + size += {{ value_type.ffi_converter() }}.computeSize(value[key]); + } + return size; + } +} + diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Object.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Object.jsm new file mode 100644 index 000000000000..41fcd96b4009 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Object.jsm @@ -0,0 +1,69 @@ +{%- let object = ci.get_object_definition(name).unwrap() %} + +class {{ object.nm() }} { + // Use `init` to instantiate this class. + // DO NOT USE THIS CONSTRUCTOR DIRECTLY + constructor(opts) { + if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) { + throw new UniFFIError("Attempting to construct an object using the JavaScript constructor directly" + + "Please use a UDL defined constructor, or the init function for the primary constructor") + } + if (!opts[constructUniffiObject] instanceof UniFFIPointer) { + throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer") + } + this[uniffiObjectPtr] = opts[constructUniffiObject]; + } + + {%- for cons in object.constructors() %} + {%- if cons.is_async() %} + /** + * An async constructor for {{ object.nm() }}. + * + * @returns {Promise<{{ object.nm() }}>}: A promise that resolves + * to a newly constructed {{ object.nm() }} + */ + {%- else %} + /** + * A constructor for {{ object.nm() }}. + * + * @returns { {{ object.nm() }} } + */ + {%- endif %} + static {{ cons.nm() }}({{cons.arg_names()}}) { + {%- call js::call_constructor(cons, type_) -%} + } + {%- endfor %} + + {%- for meth in object.methods() %} + {{ meth.nm() }}({{ meth.arg_names() }}) { + {%- call js::call_method(meth, type_, object) -%} + } + {%- endfor %} + +} + +class {{ ffi_converter }} extends FfiConverter { + static lift(value) { + const opts = {}; + opts[constructUniffiObject] = value; + return new {{ object.nm() }}(opts); + } + + static lower(value) { + return value[uniffiObjectPtr]; + } + + static read(dataStream) { + return this.lift(dataStream.readPointer{{ object.nm() }}()); + } + + static write(dataStream, value) { + dataStream.writePointer{{ object.nm() }}(value[uniffiObjectPtr]); + } + + static computeSize(value) { + return 8; + } +} + +EXPORTED_SYMBOLS.push("{{ object.nm() }}"); diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Optional.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Optional.jsm new file mode 100644 index 000000000000..ad5be63b244b --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Optional.jsm @@ -0,0 +1,36 @@ +class {{ ffi_converter }} extends FfiConverterArrayBuffer { + static checkType(name, value) { + if (value !== undefined && value !== null) { + {{ inner.ffi_converter() }}.checkType(name, value) + } + } + + static read(dataStream) { + const code = dataStream.readUint8(0); + switch (code) { + case 0: + return null + case 1: + return {{ inner.ffi_converter() }}.read(dataStream) + default: + throw UniFFIError(`Unexpected code: ${code}`); + } + } + + static write(dataStream, value) { + if (value === null || value === undefined) { + dataStream.writeUint8(0); + return; + } + dataStream.writeUint8(1); + {{ inner.ffi_converter() }}.write(dataStream, value) + } + + static computeSize(value) { + if (value === null || value === undefined) { + return 1; + } + return 1 + {{ inner.ffi_converter() }}.computeSize(value) + } +} + diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Record.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Record.jsm new file mode 100644 index 000000000000..3f9a8788a48c --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Record.jsm @@ -0,0 +1,55 @@ +{% let record = ci.get_record_definition(name).unwrap() %} + +class {{ record.nm() }} { + constructor({{ record.constructor_field_list() }}) { + {%- for field in record.fields() %} + {{ field.check_type() }}; + {%- endfor %} + + {%- for field in record.fields() %} + this.{{field.nm()}} = {{ field.nm() }}; + {%- endfor %} + } + equals(other) { + return ( + {%- for field in record.fields() %} + {{ field.type_().equals("this.{}"|format(field.nm()), "other.{}"|format(field.nm())) }}{% if !loop.last %} &&{% endif %} + {%- endfor %} + ) + } +} + +class {{ ffi_converter }} extends FfiConverter { + static lift(buf) { + return this.read(new ArrayBufferDataStream(buf)); + } + static lower(value) { + const buf = new ArrayBuffer(this.computeSize(value)); + const dataStream = new ArrayBufferDataStream(buf); + this.write(dataStream, value); + return buf; + } + static read(dataStream) { + return new {{record.nm()}}( + {%- for field in record.fields() %} + {{ field.read_datastream_fn() }}(dataStream) + {%- if !loop.last %}, {% endif %} + {%- endfor %} + ); + } + static write(dataStream, value) { + {%- for field in record.fields() %} + {{ field.write_datastream_fn() }}(dataStream, value.{{field.nm()}}); + {%- endfor %} + } + + static computeSize(value) { + let totalSize = 0; + {%- for field in record.fields() %} + totalSize += {{ field.ffi_converter() }}.computeSize(value.{{ field.nm() }}); + {%- endfor %} + return totalSize + } +} + +EXPORTED_SYMBOLS.push("{{ record.nm() }}"); diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Sequence.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Sequence.jsm new file mode 100644 index 000000000000..ef5d5e59d1a3 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Sequence.jsm @@ -0,0 +1,27 @@ +class {{ ffi_converter }} extends FfiConverterArrayBuffer { + static read(dataStream) { + const len = dataStream.readInt32(); + const arr = []; + for (let i = 0; i < len; i++) { + arr.push({{ inner.ffi_converter() }}.read(dataStream)); + } + return arr; + } + + static write(dataStream, value) { + dataStream.writeInt32(value.length); + value.forEach((innerValue) => { + {{ inner.ffi_converter() }}.write(dataStream, innerValue); + }) + } + + static computeSize(value) { + // The size of the length + let size = 4; + for (const innerValue of value) { + size += {{ inner.ffi_converter() }}.computeSize(innerValue); + } + return size; + } +} + diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/String.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/String.jsm new file mode 100644 index 000000000000..fbbde546471f --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/String.jsm @@ -0,0 +1,27 @@ + + +class FfiConverterString extends FfiConverter { + static lift(buf) { + const decoder = new TextDecoder(); + const utf8Arr = new Uint8Array(buf); + return decoder.decode(utf8Arr); + } + static lower(value) { + const encoder = new TextEncoder(); + return encoder.encode(value).buffer; + } + + static write(dataStream, value) { + dataStream.writeString(value); + } + + static read(dataStream) { + return dataStream.readString(); + } + + static computeSize(value) { + const encoder = new TextEncoder(); + return 4 + encoder.encode(value).length + } +} + diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/TopLevelFunctions.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/TopLevelFunctions.jsm new file mode 100644 index 000000000000..9f869240bc32 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/TopLevelFunctions.jsm @@ -0,0 +1,8 @@ +{%- for func in ci.function_definitions() %} +function {{ func.nm() }}({{ func.arg_names() }}) { + {% call js::call_scaffolding_function(func) %} +} + +EXPORTED_SYMBOLS.push("{{ func.nm() }}"); + +{%- endfor %} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Types.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Types.jsm new file mode 100644 index 000000000000..7c4bb8439fc3 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Types.jsm @@ -0,0 +1,66 @@ +{%- for type_ in ci.iter_types() %} +{%- let ffi_converter = type_.ffi_converter() %} +{%- match type_ %} + +{%- when Type::Boolean %} +{%- include "Boolean.jsm" %} + +{%- when Type::UInt8 %} +{%- include "UInt8.jsm" %} + +{%- when Type::UInt16 %} +{%- include "UInt16.jsm" %} + +{%- when Type::UInt32 %} +{%- include "UInt32.jsm" %} + +{%- when Type::UInt64 %} +{%- include "UInt64.jsm" %} + +{%- when Type::Int8 %} +{%- include "Int8.jsm" %} + +{%- when Type::Int16 %} +{%- include "Int16.jsm" %} + +{%- when Type::Int32 %} +{%- include "Int32.jsm" %} + +{%- when Type::Int64 %} +{%- include "Int64.jsm" %} + +{%- when Type::Float32 %} +{%- include "Float32.jsm" %} + +{%- when Type::Float64 %} +{%- include "Float64.jsm" %} + +{%- when Type::Record with (name) %} +{%- include "Record.jsm" %} + +{%- when Type::Optional with (inner) %} +{%- include "Optional.jsm" %} + +{%- when Type::String %} +{%- include "String.jsm" %} + +{%- when Type::Sequence with (inner) %} +{%- include "Sequence.jsm" %} + +{%- when Type::Map with (key_type, value_type) %} +{%- include "Map.jsm" %} + +{%- when Type::Error with (name) %} +{% include "Error.jsm" %} + +{% when Type::Enum with (name) %} +{% include "Enum.jsm" %} + +{% when Type::Object with (name) %} +{% include "Object.jsm" %} + +{%- else %} +{# TODO implement the other types #} + +{%- endmatch %} +{%- endfor %} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt16.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt16.jsm new file mode 100644 index 000000000000..b118a75d6cc6 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt16.jsm @@ -0,0 +1,26 @@ +class {{ ffi_converter }} extends FfiConverter { + static checkType(name, value) { + super.checkType(name, value); + if (!Number.isInteger(value)) { + throw TypeError(`${name} is not an integer(${value})`); + } + if (value < 0 || value > 65535) { + throw TypeError(`${name} exceeds the U16 bounds (${value})`); + } + } + static computeSize() { + return 2; + } + static lift(value) { + return value; + } + static lower(value) { + return value; + } + static write(dataStream, value) { + dataStream.writeUint16(value) + } + static read(dataStream) { + return dataStream.readUint16() + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt32.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt32.jsm new file mode 100644 index 000000000000..cf7d7c6edb80 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt32.jsm @@ -0,0 +1,26 @@ +class {{ ffi_converter }} extends FfiConverter { + static checkType(name, value) { + super.checkType(name, value); + if (!Number.isInteger(value)) { + throw TypeError(`${name} is not an integer(${value})`); + } + if (value < 0 || value > 4294967295) { + throw TypeError(`${name} exceeds the U32 bounds (${value})`); + } + } + static computeSize() { + return 4; + } + static lift(value) { + return value; + } + static lower(value) { + return value; + } + static write(dataStream, value) { + dataStream.writeUint32(value) + } + static read(dataStream) { + return dataStream.readUint32() + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt64.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt64.jsm new file mode 100644 index 000000000000..1284d7738aa7 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt64.jsm @@ -0,0 +1,26 @@ +class {{ ffi_converter }} extends FfiConverter { + static checkType(name, value) { + super.checkType(name, value); + if (!Number.isSafeInteger(value)) { + throw TypeError(`${name} exceeds the safe integer bounds (${value})`); + } + if (value < 0) { + throw TypeError(`${name} exceeds the U64 bounds (${value})`); + } + } + static computeSize() { + return 8; + } + static lift(value) { + return value; + } + static lower(value) { + return value; + } + static write(dataStream, value) { + dataStream.writeUint64(value) + } + static read(dataStream) { + return dataStream.readUint64() + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt8.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt8.jsm new file mode 100644 index 000000000000..17f0c5c54b82 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt8.jsm @@ -0,0 +1,26 @@ +class {{ ffi_converter }} extends FfiConverter { + static checkType(name, value) { + super.checkType(name, value); + if (!Number.isInteger(value)) { + throw TypeError(`${name} is not an integer(${value})`); + } + if (value < 0 || value > 256) { + throw TypeError(`${name} exceeds the U8 bounds (${value})`); + } + } + static computeSize() { + return 1; + } + static lift(value) { + return value; + } + static lower(value) { + return value; + } + static write(dataStream, value) { + dataStream.writeUint8(value) + } + static read(dataStream) { + return dataStream.readUint8() + } +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/macros.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/macros.jsm new file mode 100644 index 000000000000..d5be655da169 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/macros.jsm @@ -0,0 +1,55 @@ +{%- macro call_scaffolding_function(func) %} +{%- call _call_scaffolding_function(func, func.return_type(), "") -%} +{%- endmacro %} + +{%- macro call_constructor(cons, object_type) %} +{%- call _call_scaffolding_function(cons, Some(object_type), "") -%} +{%- endmacro %} + +{%- macro call_method(method, object_type) %} +{%- call _call_scaffolding_function(method, method.return_type(), object_type.ffi_converter()) -%} +{%- endmacro %} + +{%- macro _call_scaffolding_function(func, return_type, receiver_ffi_converter) %} + {%- match return_type %} + {%- when Some with (return_type) %} + const liftResult = (result) => {{ return_type.ffi_converter() }}.lift(result); + {%- else %} + const liftResult = (result) => undefined; + {%- endmatch %} + {%- match func.throws_type() %} + {%- when Some with (err_type) %} + const liftError = (data) => {{ err_type.ffi_converter() }}.lift(data); + {%- else %} + const liftError = null; + {%- endmatch %} + const functionCall = () => { + {%- for arg in func.arguments() %} + {{ arg.check_type() }}; + {%- endfor %} + + {%- if func.is_async() %} + return UniFFIScaffolding.callAsync( + {%- else %} + return UniFFIScaffolding.callSync( + {%- endif %} + {{ function_ids.get(ci, func.ffi_func()) }}, // {{ function_ids.name(ci, func.ffi_func()) }} + {%- if receiver_ffi_converter != "" %} + {{ receiver_ffi_converter }}.lower(this), + {%- endif %} + {%- for arg in func.arguments() %} + {{ arg.lower_fn_name() }}({{ arg.nm() }}), + {%- endfor %} + ) + } + + {%- if func.is_async() %} + try { + return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); + } catch (error) { + return Promise.reject(error) + } + {%- else %} + return handleRustResult(functionCall(), liftResult, liftError); + {%- endif %} +{%- endmacro %} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/wrapper.jsm b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/wrapper.jsm new file mode 100644 index 000000000000..8f257b98826f --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/wrapper.jsm @@ -0,0 +1,14 @@ +// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate. +// Trust me, you don't want to mess with it! + +{% import "macros.jsm" as js %} + +"use strict"; + +var EXPORTED_SYMBOLS = []; + +{% include "Helpers.jsm" %} + +{% include "Types.jsm" %} + +{% include "TopLevelFunctions.jsm" %} diff --git a/toolkit/components/uniffi-js/OwnedRustBuffer.cpp b/toolkit/components/uniffi-js/OwnedRustBuffer.cpp new file mode 100644 index 000000000000..96d9dc1fd7b4 --- /dev/null +++ b/toolkit/components/uniffi-js/OwnedRustBuffer.cpp @@ -0,0 +1,92 @@ +/* -*- 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 "nsString.h" +#include "mozilla/dom/OwnedRustBuffer.h" + +namespace mozilla::uniffi { + +using dom::ArrayBuffer; + +OwnedRustBuffer::OwnedRustBuffer(const RustBuffer& aBuf) { + mBuf = aBuf; + MOZ_ASSERT(IsValid()); +} + +Result OwnedRustBuffer::FromArrayBuffer( + const ArrayBuffer& aArrayBuffer) { + if (aArrayBuffer.Length() > INT32_MAX) { + return Err("Input ArrayBuffer is too large"_ns); + } + + RustCallStatus status{}; + RustBuffer buf = uniffi_rustbuffer_alloc( + static_cast(aArrayBuffer.Length()), &status); + buf.len = aArrayBuffer.Length(); + if (status.code != 0) { + if (status.error_buf.data) { + auto message = nsCString("uniffi_rustbuffer_alloc: "); + message.Append( + nsDependentCSubstring(reinterpret_cast(status.error_buf.data), + status.error_buf.len)); + RustCallStatus status2{}; + uniffi_rustbuffer_free(status.error_buf, &status2); + MOZ_RELEASE_ASSERT(status2.code == 0, + "Freeing a rustbuffer should never fail"); + return Err(message); + + } else { + return Err("Unknown error allocating rust buffer"_ns); + } + } + + memcpy(buf.data, aArrayBuffer.Data(), buf.len); + return OwnedRustBuffer(buf); +} + +OwnedRustBuffer::OwnedRustBuffer(OwnedRustBuffer&& aOther) : mBuf(aOther.mBuf) { + aOther.mBuf = RustBuffer{0}; +} + +OwnedRustBuffer& OwnedRustBuffer::operator=(OwnedRustBuffer&& aOther) { + if (&aOther != this) { + FreeData(); + } + mBuf = aOther.mBuf; + aOther.mBuf = RustBuffer{0}; + return *this; +} + +void OwnedRustBuffer::FreeData() { + if (IsValid()) { + RustCallStatus status{}; + uniffi_rustbuffer_free(mBuf, &status); + MOZ_RELEASE_ASSERT(status.code == 0, + "Freeing a rustbuffer should never fail"); + mBuf = {0}; + } +} + +OwnedRustBuffer::~OwnedRustBuffer() { FreeData(); } + +RustBuffer OwnedRustBuffer::IntoRustBuffer() { + RustBuffer rv = mBuf; + mBuf = {}; + return rv; +} + +JSObject* OwnedRustBuffer::IntoArrayBuffer(JSContext* cx) { + int32_t len = mBuf.len; + void* data = mBuf.data; + auto userData = MakeUnique(std::move(*this)); + return JS::NewExternalArrayBuffer(cx, len, data, &ArrayBufferFreeFunc, + userData.release()); +} + +void OwnedRustBuffer::ArrayBufferFreeFunc(void* contents, void* userData) { + UniquePtr buf{reinterpret_cast(userData)}; +} +} // namespace mozilla::uniffi diff --git a/toolkit/components/uniffi-js/OwnedRustBuffer.h b/toolkit/components/uniffi-js/OwnedRustBuffer.h new file mode 100644 index 000000000000..d43a23330671 --- /dev/null +++ b/toolkit/components/uniffi-js/OwnedRustBuffer.h @@ -0,0 +1,69 @@ +/* -*- 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_OwnedRustBuffer_h +#define mozilla_OwnedRustBuffer_h + +#include "mozilla/ErrorResult.h" +#include "mozilla/ResultVariant.h" +#include "mozilla/dom/TypedArray.h" +#include "mozilla/dom/UniFFIRust.h" + +namespace mozilla::uniffi { + +// RustBuffer that's owned by the JS code and handles the memory management +class OwnedRustBuffer final { + private: + RustBuffer mBuf; + + void FreeData(); + + public: + // The default constructor creates an invalid OwnedRustBuffer + OwnedRustBuffer() : mBuf{0} {}; + + // Constructor for creating an OwnedRustBuffer from a raw RustBuffer struct + // that was returned by Rust (therefore we now own the RustBuffer). + explicit OwnedRustBuffer(const RustBuffer& aBuf); + + // Manual implementation of move constructor and assignment operator. + OwnedRustBuffer(OwnedRustBuffer&& aOther); + OwnedRustBuffer& operator=(OwnedRustBuffer&& aOther); + + // Delete copy & move constructor as this type is non-copyable. + OwnedRustBuffer(const OwnedRustBuffer&) = delete; + OwnedRustBuffer& operator=(const OwnedRustBuffer&) = delete; + + // Destructor that frees the RustBuffer if it is still valid + ~OwnedRustBuffer(); + + // Constructor for creating an OwnedRustBuffer from an ArrayBuffer. Will set + // aError to failed and construct an invalid OwnedRustBuffer if the + // conversion failed. + static Result FromArrayBuffer( + const mozilla::dom::ArrayBuffer& aArrayBuffer); + + // Moves the buffer out of this `OwnedArrayBuffer` into a raw `RustBuffer` + // struct. The raw struct must be passed into a Rust function, transfering + // ownership to Rust. After this call the buffer will no longer be valid. + RustBuffer IntoRustBuffer(); + + // Moves the buffer out of this `OwnedArrayBuffer` into a JS ArrayBuffer. + // This transfers ownership into the JS engine. After this call the buffer + // will no longer be valid. + JSObject* IntoArrayBuffer(JSContext* cx); + + // Is this RustBuffer pointing to valid data? + bool IsValid() const { return mBuf.data != nullptr; } + + private: + // Helper function used by IntoArrayBuffer. + static void ArrayBufferFreeFunc(void* contents, void* userData); +}; + +} // namespace mozilla::uniffi + +#endif // mozilla_OwnedRustBuffer_h diff --git a/toolkit/components/uniffi-js/README.md b/toolkit/components/uniffi-js/README.md new file mode 100644 index 000000000000..addd0b4bcc52 --- /dev/null +++ b/toolkit/components/uniffi-js/README.md @@ -0,0 +1,23 @@ +# uniffi-js + +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 code for all + non-testing UDL files. + - UniFFIFixtureScaffolding.cpp contains generated code for test fixture UDL + files. It's only compiled if `--enable-uniffi-fixtures` is set. + - UniFFIScaffolding.cpp is a facade that wraps UniFFIFixtureScaffolding, and + UniFFIGeneratedScaffolding if enabled, to implement the interface. + +- `ScaffoldingConverter.h`, `ScaffoldingCall.h` contain generic code to make + the scaffolding calls. In general, we try to keep the logic of the calls in + these files and limit the generated code to routing call IDs to template + classes defined here. + +- `OwnedRustBuffer.*` implements a C++ class to help manager ownership of a RustBuffer. + +- `UniFFIRust.h` contains definitions for the C functions that UniFFI exports. diff --git a/toolkit/components/uniffi-js/ScaffoldingCall.h b/toolkit/components/uniffi-js/ScaffoldingCall.h new file mode 100644 index 000000000000..bd6efd8aad63 --- /dev/null +++ b/toolkit/components/uniffi-js/ScaffoldingCall.h @@ -0,0 +1,260 @@ +/* -*- 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_ScaffoldingCall_h +#define mozilla_ScaffoldingCall_h + +#include +#include +#include "nsIGlobalObject.h" +#include "nsPrintfCString.h" +#include "mozilla/MozPromise.h" +#include "mozilla/ResultVariant.h" +#include "mozilla/dom/OwnedRustBuffer.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/ScaffoldingConverter.h" +#include "mozilla/dom/UniFFIBinding.h" +#include "mozilla/dom/UniFFIRust.h" + +namespace mozilla::uniffi { + +// Low-level result of calling a scaffolding function +// +// This stores what Rust returned in order to convert it into +// UniFFIScaffoldingCallResult +template +struct RustCallResult { + ReturnType mReturnValue; + RustCallStatus mCallStatus = {}; +}; + +template <> +struct RustCallResult { + RustCallStatus mCallStatus = {}; +}; + +// Does the work required to call a scaffolding function +// +// This class is generic over the type signature of the scaffolding function. +// This seems better than being generic over the functions themselves, since it +// saves space whenever 2 functions share a signature. +template +class ScaffoldingCallHandler { + public: + // Pointer to a scaffolding function that can be called by this + // ScaffoldingConverter + using ScaffoldingFunc = typename ReturnConverter::RustType (*)( + typename ArgConverters::RustType..., RustCallStatus*); + + // Perform an async scaffolding call + static already_AddRefed CallAsync( + ScaffoldingFunc aScaffoldingFunc, const dom::GlobalObject& aGlobal, + const dom::Sequence& aArgs, + const nsLiteralCString& aFuncName, ErrorResult& aError) { + auto convertResult = ConvertJsArgs(aArgs); + if (convertResult.isErr()) { + aError.ThrowUnknownError(aFuncName + convertResult.unwrapErr()); + return nullptr; + } + auto convertedArgs = convertResult.unwrap(); + + // Create the promise that we return to JS + nsCOMPtr xpcomGlobal = + do_QueryInterface(aGlobal.GetAsSupports()); + RefPtr 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 typename TaskPromiseType::Private(aFuncName.get()); + nsresult dispatchResult = NS_DispatchBackgroundTask( + NS_NewRunnableFunction(aFuncName.get(), + [args = std::move(convertedArgs), taskPromise, + aScaffoldingFunc, aFuncName]() mutable { + auto callResult = CallScaffoldingFunc( + aScaffoldingFunc, std::move(args)); + taskPromise->Resolve(std::move(callResult), + aFuncName.get()); + }), + NS_DISPATCH_EVENT_MAY_BLOCK); + if (NS_FAILED(dispatchResult)) { + taskPromise->Reject(dispatchResult, aFuncName.get()); + } + + // When the background task promise completes, resolve the JS promise + taskPromise->Then( + GetCurrentSerialEventTarget(), aFuncName.get(), + [xpcomGlobal, returnPromise, + aFuncName](typename TaskPromiseType::ResolveOrRejectValue&& aResult) { + if (!aResult.IsResolve()) { + returnPromise->MaybeRejectWithUnknownError(aFuncName); + return; + } + + dom::AutoEntryScript aes(xpcomGlobal, aFuncName.get()); + dom::RootedDictionary returnValue( + aes.cx()); + + ReturnResult(aes.cx(), aResult.ResolveValue(), returnValue, + aFuncName); + returnPromise->MaybeResolve(returnValue); + }); + + // Return the JS promise, using forget() to convert it to already_AddRefed + return returnPromise.forget(); + } + + // Perform an sync scaffolding call + // + // aFuncName should be a literal C string + static void CallSync( + ScaffoldingFunc aScaffoldingFunc, const dom::GlobalObject& aGlobal, + const dom::Sequence& aArgs, + dom::RootedDictionary& aReturnValue, + const nsLiteralCString& aFuncName, ErrorResult& aError) { + auto convertResult = ConvertJsArgs(aArgs); + if (convertResult.isErr()) { + aError.ThrowUnknownError(aFuncName + convertResult.unwrapErr()); + return; + } + + auto callResult = CallScaffoldingFunc(aScaffoldingFunc, + std::move(convertResult.unwrap())); + + ReturnResult(aGlobal.Context(), callResult, aReturnValue, aFuncName); + } + + private: + using RustArgs = std::tuple; + using IntermediateArgs = + std::tuple; + using RustCallResult = RustCallResult; + using TaskPromiseType = MozPromise; + + template + using NthArgConverter = + typename std::tuple_element>::type; + + // Convert arguments from JS + // + // This should be called in the main thread + static Result ConvertJsArgs( + const dom::Sequence& aArgs) { + IntermediateArgs convertedArgs; + if (aArgs.Length() != std::tuple_size_v) { + return mozilla::Err("Wrong argument count"_ns); + } + auto result = PrepareArgsHelper<0>(aArgs, convertedArgs); + return result.map([&](auto _) { return std::move(convertedArgs); }); + } + + // Helper function for PrepareArgs that uses c++ magic to help with iteration + template + static Result PrepareArgsHelper( + const dom::Sequence& aArgs, + IntermediateArgs& aConvertedArgs) { + if constexpr (I >= sizeof...(ArgConverters)) { + // Iteration complete + return mozilla::Ok(); + } else { + // Single iteration step + auto result = NthArgConverter::FromJs(aArgs[I]); + if (result.isOk()) { + // The conversion worked, store our result and move on to the next + std::get(aConvertedArgs) = result.unwrap(); + return PrepareArgsHelper(aArgs, aConvertedArgs); + } else { + // The conversion failed, return an error and don't continue + return mozilla::Err(result.unwrapErr() + + nsPrintfCString(" (arg %ld)", I)); + } + } + } + + // Call the scaffolding function + // + // For async calls this should be called in the worker thread + static RustCallResult CallScaffoldingFunc(ScaffoldingFunc aFunc, + IntermediateArgs&& aArgs) { + return CallScaffoldingFuncHelper( + aFunc, std::move(aArgs), std::index_sequence_for()); + } + + // Helper function for CallScaffoldingFunc that uses c++ magic to help with + // iteration + template + static RustCallResult CallScaffoldingFuncHelper( + ScaffoldingFunc aFunc, IntermediateArgs&& aArgs, + std::index_sequence seq) { + RustCallResult result; + + auto makeCall = [&]() mutable { + return aFunc( + NthArgConverter::IntoRust(std::move(std::get(aArgs)))..., + &result.mCallStatus); + }; + if constexpr (std::is_void_v) { + makeCall(); + } else { + result.mReturnValue = makeCall(); + } + return result; + } + + // Return the result of the scaffolding call back to JS + // + // This should be called on the main thread + static void ReturnResult( + JSContext* aContext, RustCallResult& aCallResult, + dom::RootedDictionary& aReturnValue, + const nsLiteralCString& aFuncName) { + switch (aCallResult.mCallStatus.code) { + case RUST_CALL_SUCCESS: { + aReturnValue.mCode = dom::UniFFIScaffoldingCallCode::Success; + if constexpr (!std::is_void_v) { + auto convertResult = + ReturnConverter::FromRust(aCallResult.mReturnValue); + if (convertResult.isOk()) { + ReturnConverter::IntoJs(aContext, std::move(convertResult.unwrap()), + aReturnValue.mData.Construct()); + } else { + aReturnValue.mCode = dom::UniFFIScaffoldingCallCode::Internal_error; + aReturnValue.mInternalErrorMessage.Construct( + aFuncName + " converting result: "_ns + + convertResult.unwrapErr()); + } + } + break; + } + + case RUST_CALL_ERROR: { + // Rust Err() value. Populate data with the `RustBuffer` containing the + // error + aReturnValue.mCode = dom::UniFFIScaffoldingCallCode::Error; + aReturnValue.mData.Construct().SetAsArrayBuffer().Init( + OwnedRustBuffer(aCallResult.mCallStatus.error_buf) + .IntoArrayBuffer(aContext)); + break; + } + + default: { + // This indicates a RustError, which shouldn't happen in practice since + // FF sets panic=abort + aReturnValue.mCode = dom::UniFFIScaffoldingCallCode::Internal_error; + aReturnValue.mInternalErrorMessage.Construct(aFuncName + + " Unexpected Error"_ns); + break; + } + } + } +}; + +} // namespace mozilla::uniffi + +#endif // mozilla_ScaffoldingCall_h diff --git a/toolkit/components/uniffi-js/ScaffoldingConverter.h b/toolkit/components/uniffi-js/ScaffoldingConverter.h new file mode 100644 index 000000000000..59829938c2e2 --- /dev/null +++ b/toolkit/components/uniffi-js/ScaffoldingConverter.h @@ -0,0 +1,206 @@ +/* -*- 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 +#include +#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 { + +class ScaffoldingConverterTagDefault {}; + +// 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 +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 mozilla::Result FromJs( + const dom::ScaffoldingType& aValue) { + if (!aValue.IsDouble()) { + return Err("Bad argument type"_ns); + } + double value = aValue.GetAsDouble(); + + if (std::isnan(value)) { + return Err("NaN not allowed"_ns); + } + + if constexpr (std::is_integral::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::min() || + value > dom::PrimitiveConversionTraits_Limits::max()) { + return Err("Out of bounds"_ns); + } + } + + // Don't check float bounds for a few reasons. + // - It's difficult because + // PrimitiveConversionTraits_Limits::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. + + RustType rv = static_cast(value); + if constexpr (std::is_integral::value) { + if (rv != value) { + return Err("Not an integer"_ns); + } + } + + return 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 RustTypes are POD types + // + // If this succeeds then IntoJs is also guaranteed to succeed + static mozilla::Result FromRust( + RustType aValue) { + if constexpr (std::is_same::value || + std::is_same::value) { + // Check that the value can fit in a double (only needed for 64 bit types) + if (aValue < dom::PrimitiveConversionTraits_Limits::min() || + aValue > dom::PrimitiveConversionTraits_Limits::max()) { + return Err("Out of bounds"_ns); + } + } + if constexpr (std::is_floating_point::value) { + if (std::isnan(aValue)) { + return Err("NaN not allowed"_ns); + } + } + 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::ScaffoldingType& aDest) { + aDest.SetAsDouble() = aValue; + } +}; + +template <> +class ScaffoldingConverter { + public: + using RustType = RustBuffer; + using IntermediateType = OwnedRustBuffer; + + static mozilla::Result FromJs( + const dom::ScaffoldingType& aValue) { + if (!aValue.IsArrayBuffer()) { + return Err("Bad argument type"_ns); + } + + const dom::ArrayBuffer& arrayBuf = aValue.GetAsArrayBuffer(); + arrayBuf.ComputeState(); + return OwnedRustBuffer::FromArrayBuffer(arrayBuf); + } + + static RustBuffer IntoRust(OwnedRustBuffer&& aValue) { + return aValue.IntoRustBuffer(); + } + + static mozilla::Result FromRust( + RustBuffer aValue) { + return OwnedRustBuffer(aValue); + } + + static void IntoJs(JSContext* aContext, OwnedRustBuffer&& aValue, + dom::ScaffoldingType& aDest) { + aDest.SetAsArrayBuffer().Init(aValue.IntoArrayBuffer(aContext)); + } +}; + +// ScaffoldingConverter for object pointers +template +class ScaffoldingObjectConverter { + public: + using RustType = void*; + using IntermediateType = void*; + + static mozilla::Result FromJs( + const dom::ScaffoldingType& aValue) { + if (!aValue.IsUniFFIPointer()) { + return Err("Bad argument type"_ns); + } + dom::UniFFIPointer& value = aValue.GetAsUniFFIPointer(); + if (!value.IsSamePtrType(PointerType)) { + return Err("Bad pointer type"_ns); + } + return value.GetPtr(); + } + + static void* IntoRust(void* aValue) { return aValue; } + + static mozilla::Result FromRust(void* aValue) { + return aValue; + } + + static void IntoJs(JSContext* aContext, void* aValue, + dom::ScaffoldingType& aDest) { + 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 { + public: + using RustType = void; +}; + +} // namespace mozilla::uniffi + +#endif // mozilla_ScaffoldingConverter_h diff --git a/toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp b/toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp new file mode 100644 index 000000000000..46b9ec9a3992 --- /dev/null +++ b/toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp @@ -0,0 +1,992 @@ +// Generated by uniffi-bindgen-gecko-js. DO NOT EDIT. + +#include "nsString.h" +#include "nsPrintfCString.h" +#include "mozilla/Maybe.h" +#include "mozilla/dom/UniFFIScaffolding.h" +#include "mozilla/dom/ScaffoldingCall.h" + +namespace mozilla::uniffi { + +using dom::ArrayBuffer; +using dom::GlobalObject; +using dom::RootedDictionary; +using dom::Promise; +using dom::ScaffoldingType; +using dom::Sequence; +using dom::UniFFIPointer; +using dom::UniFFIScaffoldingCallResult; + +// Define scaffolding functions from UniFFI +extern "C" { + double geometry_ba8c_gradient(RustBuffer, RustCallStatus*); + RustBuffer geometry_ba8c_intersection(RustBuffer, RustBuffer, RustCallStatus*); + uint64_t arithmetic_77d6_add(uint64_t, uint64_t, RustCallStatus*); + uint64_t arithmetic_77d6_sub(uint64_t, uint64_t, RustCallStatus*); + uint64_t arithmetic_77d6_div(uint64_t, uint64_t, RustCallStatus*); + int8_t arithmetic_77d6_equal(uint64_t, uint64_t, RustCallStatus*); + void ffi_rondpoint_84bf_Retourneur_object_free(void *, RustCallStatus*); + void * rondpoint_84bf_Retourneur_new(RustCallStatus*); + int8_t rondpoint_84bf_Retourneur_identique_i8(void *, int8_t, RustCallStatus*); + uint8_t rondpoint_84bf_Retourneur_identique_u8(void *, uint8_t, RustCallStatus*); + int16_t rondpoint_84bf_Retourneur_identique_i16(void *, int16_t, RustCallStatus*); + uint16_t rondpoint_84bf_Retourneur_identique_u16(void *, uint16_t, RustCallStatus*); + int32_t rondpoint_84bf_Retourneur_identique_i32(void *, int32_t, RustCallStatus*); + uint32_t rondpoint_84bf_Retourneur_identique_u32(void *, uint32_t, RustCallStatus*); + int64_t rondpoint_84bf_Retourneur_identique_i64(void *, int64_t, RustCallStatus*); + uint64_t rondpoint_84bf_Retourneur_identique_u64(void *, uint64_t, RustCallStatus*); + float rondpoint_84bf_Retourneur_identique_float(void *, float, RustCallStatus*); + double rondpoint_84bf_Retourneur_identique_double(void *, double, RustCallStatus*); + int8_t rondpoint_84bf_Retourneur_identique_boolean(void *, int8_t, RustCallStatus*); + RustBuffer rondpoint_84bf_Retourneur_identique_string(void *, RustBuffer, RustCallStatus*); + RustBuffer rondpoint_84bf_Retourneur_identique_nombres_signes(void *, RustBuffer, RustCallStatus*); + RustBuffer rondpoint_84bf_Retourneur_identique_nombres(void *, RustBuffer, RustCallStatus*); + RustBuffer rondpoint_84bf_Retourneur_identique_optionneur_dictionnaire(void *, RustBuffer, RustCallStatus*); + void ffi_rondpoint_84bf_Stringifier_object_free(void *, RustCallStatus*); + void * rondpoint_84bf_Stringifier_new(RustCallStatus*); + RustBuffer rondpoint_84bf_Stringifier_well_known_string(void *, RustBuffer, RustCallStatus*); + RustBuffer rondpoint_84bf_Stringifier_to_string_i8(void *, int8_t, RustCallStatus*); + RustBuffer rondpoint_84bf_Stringifier_to_string_u8(void *, uint8_t, RustCallStatus*); + RustBuffer rondpoint_84bf_Stringifier_to_string_i16(void *, int16_t, RustCallStatus*); + RustBuffer rondpoint_84bf_Stringifier_to_string_u16(void *, uint16_t, RustCallStatus*); + RustBuffer rondpoint_84bf_Stringifier_to_string_i32(void *, int32_t, RustCallStatus*); + RustBuffer rondpoint_84bf_Stringifier_to_string_u32(void *, uint32_t, RustCallStatus*); + RustBuffer rondpoint_84bf_Stringifier_to_string_i64(void *, int64_t, RustCallStatus*); + RustBuffer rondpoint_84bf_Stringifier_to_string_u64(void *, uint64_t, RustCallStatus*); + RustBuffer rondpoint_84bf_Stringifier_to_string_float(void *, float, RustCallStatus*); + RustBuffer rondpoint_84bf_Stringifier_to_string_double(void *, double, RustCallStatus*); + RustBuffer rondpoint_84bf_Stringifier_to_string_boolean(void *, int8_t, RustCallStatus*); + void ffi_rondpoint_84bf_Optionneur_object_free(void *, RustCallStatus*); + void * rondpoint_84bf_Optionneur_new(RustCallStatus*); + int8_t rondpoint_84bf_Optionneur_sinon_boolean(void *, int8_t, RustCallStatus*); + RustBuffer rondpoint_84bf_Optionneur_sinon_string(void *, RustBuffer, RustCallStatus*); + RustBuffer rondpoint_84bf_Optionneur_sinon_sequence(void *, RustBuffer, RustCallStatus*); + RustBuffer rondpoint_84bf_Optionneur_sinon_null(void *, RustBuffer, RustCallStatus*); + RustBuffer rondpoint_84bf_Optionneur_sinon_zero(void *, RustBuffer, RustCallStatus*); + uint8_t rondpoint_84bf_Optionneur_sinon_u8_dec(void *, uint8_t, RustCallStatus*); + int8_t rondpoint_84bf_Optionneur_sinon_i8_dec(void *, int8_t, RustCallStatus*); + uint16_t rondpoint_84bf_Optionneur_sinon_u16_dec(void *, uint16_t, RustCallStatus*); + int16_t rondpoint_84bf_Optionneur_sinon_i16_dec(void *, int16_t, RustCallStatus*); + uint32_t rondpoint_84bf_Optionneur_sinon_u32_dec(void *, uint32_t, RustCallStatus*); + int32_t rondpoint_84bf_Optionneur_sinon_i32_dec(void *, int32_t, RustCallStatus*); + uint64_t rondpoint_84bf_Optionneur_sinon_u64_dec(void *, uint64_t, RustCallStatus*); + int64_t rondpoint_84bf_Optionneur_sinon_i64_dec(void *, int64_t, RustCallStatus*); + uint8_t rondpoint_84bf_Optionneur_sinon_u8_hex(void *, uint8_t, RustCallStatus*); + int8_t rondpoint_84bf_Optionneur_sinon_i8_hex(void *, int8_t, RustCallStatus*); + uint16_t rondpoint_84bf_Optionneur_sinon_u16_hex(void *, uint16_t, RustCallStatus*); + int16_t rondpoint_84bf_Optionneur_sinon_i16_hex(void *, int16_t, RustCallStatus*); + uint32_t rondpoint_84bf_Optionneur_sinon_u32_hex(void *, uint32_t, RustCallStatus*); + int32_t rondpoint_84bf_Optionneur_sinon_i32_hex(void *, int32_t, RustCallStatus*); + uint64_t rondpoint_84bf_Optionneur_sinon_u64_hex(void *, uint64_t, RustCallStatus*); + int64_t rondpoint_84bf_Optionneur_sinon_i64_hex(void *, int64_t, RustCallStatus*); + uint32_t rondpoint_84bf_Optionneur_sinon_u32_oct(void *, uint32_t, RustCallStatus*); + float rondpoint_84bf_Optionneur_sinon_f32(void *, float, RustCallStatus*); + double rondpoint_84bf_Optionneur_sinon_f64(void *, double, RustCallStatus*); + RustBuffer rondpoint_84bf_Optionneur_sinon_enum(void *, RustBuffer, RustCallStatus*); + RustBuffer rondpoint_84bf_copie_dictionnaire(RustBuffer, RustCallStatus*); + RustBuffer rondpoint_84bf_copie_enumeration(RustBuffer, RustCallStatus*); + RustBuffer rondpoint_84bf_copie_enumerations(RustBuffer, RustCallStatus*); + RustBuffer rondpoint_84bf_copie_carte(RustBuffer, RustCallStatus*); + int8_t rondpoint_84bf_switcheroo(int8_t, RustCallStatus*); + void ffi_sprites_f59e_Sprite_object_free(void *, RustCallStatus*); + void * sprites_f59e_Sprite_new(RustBuffer, RustCallStatus*); + void * sprites_f59e_Sprite_new_relative_to(RustBuffer, RustBuffer, RustCallStatus*); + RustBuffer sprites_f59e_Sprite_get_position(void *, RustCallStatus*); + void sprites_f59e_Sprite_move_to(void *, RustBuffer, RustCallStatus*); + void sprites_f59e_Sprite_move_by(void *, RustBuffer, RustCallStatus*); + RustBuffer sprites_f59e_translate(RustBuffer, RustBuffer, RustCallStatus*); + void ffi_todolist_9473_TodoList_object_free(void *, RustCallStatus*); + void * todolist_9473_TodoList_new(RustCallStatus*); + void todolist_9473_TodoList_add_item(void *, RustBuffer, RustCallStatus*); + void todolist_9473_TodoList_add_entry(void *, RustBuffer, RustCallStatus*); + RustBuffer todolist_9473_TodoList_get_entries(void *, RustCallStatus*); + RustBuffer todolist_9473_TodoList_get_items(void *, RustCallStatus*); + void todolist_9473_TodoList_add_entries(void *, RustBuffer, RustCallStatus*); + void todolist_9473_TodoList_add_items(void *, RustBuffer, RustCallStatus*); + RustBuffer todolist_9473_TodoList_get_last_entry(void *, RustCallStatus*); + RustBuffer todolist_9473_TodoList_get_last(void *, RustCallStatus*); + RustBuffer todolist_9473_TodoList_get_first(void *, RustCallStatus*); + void todolist_9473_TodoList_clear_item(void *, RustBuffer, RustCallStatus*); + void todolist_9473_TodoList_make_default(void *, RustCallStatus*); + RustBuffer todolist_9473_get_default_list(RustCallStatus*); + void todolist_9473_set_default_list(void *, RustCallStatus*); + RustBuffer todolist_9473_create_entry_with(RustBuffer, RustCallStatus*); +} + +// Define pointer types +const static mozilla::uniffi::UniFFIPointerType kRondpointRetourneurPointerType { + "rondpoint::Retourneur"_ns, + ffi_rondpoint_84bf_Retourneur_object_free +}; +const static mozilla::uniffi::UniFFIPointerType kRondpointStringifierPointerType { + "rondpoint::Stringifier"_ns, + ffi_rondpoint_84bf_Stringifier_object_free +}; +const static mozilla::uniffi::UniFFIPointerType kRondpointOptionneurPointerType { + "rondpoint::Optionneur"_ns, + ffi_rondpoint_84bf_Optionneur_object_free +}; +const static mozilla::uniffi::UniFFIPointerType kSpritesSpritePointerType { + "sprites::Sprite"_ns, + ffi_sprites_f59e_Sprite_object_free +}; +const static mozilla::uniffi::UniFFIPointerType kTodolistTodoListPointerType { + "todolist::TodoList"_ns, + ffi_todolist_9473_TodoList_object_free +}; + +Maybe> UniFFIFixturesCallAsync(const GlobalObject& aGlobal, uint64_t aId, const Sequence& aArgs, ErrorResult& aError) { + switch (aId) { + case 0: { // geometry:geometry_ba8c_gradient + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(geometry_ba8c_gradient, aGlobal, aArgs, "geometry_ba8c_gradient: "_ns, aError)); + } + case 1: { // geometry:geometry_ba8c_intersection + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(geometry_ba8c_intersection, aGlobal, aArgs, "geometry_ba8c_intersection: "_ns, aError)); + } + case 2: { // arithmetic:arithmetic_77d6_add + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(arithmetic_77d6_add, aGlobal, aArgs, "arithmetic_77d6_add: "_ns, aError)); + } + case 3: { // arithmetic:arithmetic_77d6_sub + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(arithmetic_77d6_sub, aGlobal, aArgs, "arithmetic_77d6_sub: "_ns, aError)); + } + case 4: { // arithmetic:arithmetic_77d6_div + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(arithmetic_77d6_div, aGlobal, aArgs, "arithmetic_77d6_div: "_ns, aError)); + } + case 5: { // arithmetic:arithmetic_77d6_equal + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(arithmetic_77d6_equal, aGlobal, aArgs, "arithmetic_77d6_equal: "_ns, aError)); + } + case 6: { // rondpoint:rondpoint_84bf_Retourneur_new + using CallHandler = ScaffoldingCallHandler>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_new, aGlobal, aArgs, "rondpoint_84bf_Retourneur_new: "_ns, aError)); + } + case 7: { // rondpoint:rondpoint_84bf_Retourneur_identique_i8 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_i8, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_i8: "_ns, aError)); + } + case 8: { // rondpoint:rondpoint_84bf_Retourneur_identique_u8 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_u8, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_u8: "_ns, aError)); + } + case 9: { // rondpoint:rondpoint_84bf_Retourneur_identique_i16 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_i16, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_i16: "_ns, aError)); + } + case 10: { // rondpoint:rondpoint_84bf_Retourneur_identique_u16 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_u16, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_u16: "_ns, aError)); + } + case 11: { // rondpoint:rondpoint_84bf_Retourneur_identique_i32 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_i32, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_i32: "_ns, aError)); + } + case 12: { // rondpoint:rondpoint_84bf_Retourneur_identique_u32 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_u32, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_u32: "_ns, aError)); + } + case 13: { // rondpoint:rondpoint_84bf_Retourneur_identique_i64 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_i64, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_i64: "_ns, aError)); + } + case 14: { // rondpoint:rondpoint_84bf_Retourneur_identique_u64 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_u64, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_u64: "_ns, aError)); + } + case 15: { // rondpoint:rondpoint_84bf_Retourneur_identique_float + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_float, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_float: "_ns, aError)); + } + case 16: { // rondpoint:rondpoint_84bf_Retourneur_identique_double + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_double, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_double: "_ns, aError)); + } + case 17: { // rondpoint:rondpoint_84bf_Retourneur_identique_boolean + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_boolean, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_boolean: "_ns, aError)); + } + case 18: { // rondpoint:rondpoint_84bf_Retourneur_identique_string + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_string, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_string: "_ns, aError)); + } + case 19: { // rondpoint:rondpoint_84bf_Retourneur_identique_nombres_signes + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_nombres_signes, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_nombres_signes: "_ns, aError)); + } + case 20: { // rondpoint:rondpoint_84bf_Retourneur_identique_nombres + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_nombres, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_nombres: "_ns, aError)); + } + case 21: { // rondpoint:rondpoint_84bf_Retourneur_identique_optionneur_dictionnaire + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Retourneur_identique_optionneur_dictionnaire, aGlobal, aArgs, "rondpoint_84bf_Retourneur_identique_optionneur_dictionnaire: "_ns, aError)); + } + case 22: { // rondpoint:rondpoint_84bf_Stringifier_new + using CallHandler = ScaffoldingCallHandler>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Stringifier_new, aGlobal, aArgs, "rondpoint_84bf_Stringifier_new: "_ns, aError)); + } + case 23: { // rondpoint:rondpoint_84bf_Stringifier_well_known_string + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Stringifier_well_known_string, aGlobal, aArgs, "rondpoint_84bf_Stringifier_well_known_string: "_ns, aError)); + } + case 24: { // rondpoint:rondpoint_84bf_Stringifier_to_string_i8 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Stringifier_to_string_i8, aGlobal, aArgs, "rondpoint_84bf_Stringifier_to_string_i8: "_ns, aError)); + } + case 25: { // rondpoint:rondpoint_84bf_Stringifier_to_string_u8 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Stringifier_to_string_u8, aGlobal, aArgs, "rondpoint_84bf_Stringifier_to_string_u8: "_ns, aError)); + } + case 26: { // rondpoint:rondpoint_84bf_Stringifier_to_string_i16 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Stringifier_to_string_i16, aGlobal, aArgs, "rondpoint_84bf_Stringifier_to_string_i16: "_ns, aError)); + } + case 27: { // rondpoint:rondpoint_84bf_Stringifier_to_string_u16 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Stringifier_to_string_u16, aGlobal, aArgs, "rondpoint_84bf_Stringifier_to_string_u16: "_ns, aError)); + } + case 28: { // rondpoint:rondpoint_84bf_Stringifier_to_string_i32 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Stringifier_to_string_i32, aGlobal, aArgs, "rondpoint_84bf_Stringifier_to_string_i32: "_ns, aError)); + } + case 29: { // rondpoint:rondpoint_84bf_Stringifier_to_string_u32 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Stringifier_to_string_u32, aGlobal, aArgs, "rondpoint_84bf_Stringifier_to_string_u32: "_ns, aError)); + } + case 30: { // rondpoint:rondpoint_84bf_Stringifier_to_string_i64 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Stringifier_to_string_i64, aGlobal, aArgs, "rondpoint_84bf_Stringifier_to_string_i64: "_ns, aError)); + } + case 31: { // rondpoint:rondpoint_84bf_Stringifier_to_string_u64 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Stringifier_to_string_u64, aGlobal, aArgs, "rondpoint_84bf_Stringifier_to_string_u64: "_ns, aError)); + } + case 32: { // rondpoint:rondpoint_84bf_Stringifier_to_string_float + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Stringifier_to_string_float, aGlobal, aArgs, "rondpoint_84bf_Stringifier_to_string_float: "_ns, aError)); + } + case 33: { // rondpoint:rondpoint_84bf_Stringifier_to_string_double + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Stringifier_to_string_double, aGlobal, aArgs, "rondpoint_84bf_Stringifier_to_string_double: "_ns, aError)); + } + case 34: { // rondpoint:rondpoint_84bf_Stringifier_to_string_boolean + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Stringifier_to_string_boolean, aGlobal, aArgs, "rondpoint_84bf_Stringifier_to_string_boolean: "_ns, aError)); + } + case 35: { // rondpoint:rondpoint_84bf_Optionneur_new + using CallHandler = ScaffoldingCallHandler>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_new, aGlobal, aArgs, "rondpoint_84bf_Optionneur_new: "_ns, aError)); + } + case 36: { // rondpoint:rondpoint_84bf_Optionneur_sinon_boolean + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_boolean, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_boolean: "_ns, aError)); + } + case 37: { // rondpoint:rondpoint_84bf_Optionneur_sinon_string + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_string, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_string: "_ns, aError)); + } + case 38: { // rondpoint:rondpoint_84bf_Optionneur_sinon_sequence + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_sequence, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_sequence: "_ns, aError)); + } + case 39: { // rondpoint:rondpoint_84bf_Optionneur_sinon_null + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_null, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_null: "_ns, aError)); + } + case 40: { // rondpoint:rondpoint_84bf_Optionneur_sinon_zero + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_zero, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_zero: "_ns, aError)); + } + case 41: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u8_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_u8_dec, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_u8_dec: "_ns, aError)); + } + case 42: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i8_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_i8_dec, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_i8_dec: "_ns, aError)); + } + case 43: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u16_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_u16_dec, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_u16_dec: "_ns, aError)); + } + case 44: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i16_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_i16_dec, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_i16_dec: "_ns, aError)); + } + case 45: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u32_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_u32_dec, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_u32_dec: "_ns, aError)); + } + case 46: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i32_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_i32_dec, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_i32_dec: "_ns, aError)); + } + case 47: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u64_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_u64_dec, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_u64_dec: "_ns, aError)); + } + case 48: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i64_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_i64_dec, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_i64_dec: "_ns, aError)); + } + case 49: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u8_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_u8_hex, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_u8_hex: "_ns, aError)); + } + case 50: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i8_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_i8_hex, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_i8_hex: "_ns, aError)); + } + case 51: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u16_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_u16_hex, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_u16_hex: "_ns, aError)); + } + case 52: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i16_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_i16_hex, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_i16_hex: "_ns, aError)); + } + case 53: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u32_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_u32_hex, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_u32_hex: "_ns, aError)); + } + case 54: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i32_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_i32_hex, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_i32_hex: "_ns, aError)); + } + case 55: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u64_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_u64_hex, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_u64_hex: "_ns, aError)); + } + case 56: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i64_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_i64_hex, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_i64_hex: "_ns, aError)); + } + case 57: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u32_oct + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_u32_oct, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_u32_oct: "_ns, aError)); + } + case 58: { // rondpoint:rondpoint_84bf_Optionneur_sinon_f32 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_f32, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_f32: "_ns, aError)); + } + case 59: { // rondpoint:rondpoint_84bf_Optionneur_sinon_f64 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_f64, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_f64: "_ns, aError)); + } + case 60: { // rondpoint:rondpoint_84bf_Optionneur_sinon_enum + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_Optionneur_sinon_enum, aGlobal, aArgs, "rondpoint_84bf_Optionneur_sinon_enum: "_ns, aError)); + } + case 61: { // rondpoint:rondpoint_84bf_copie_dictionnaire + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_copie_dictionnaire, aGlobal, aArgs, "rondpoint_84bf_copie_dictionnaire: "_ns, aError)); + } + case 62: { // rondpoint:rondpoint_84bf_copie_enumeration + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_copie_enumeration, aGlobal, aArgs, "rondpoint_84bf_copie_enumeration: "_ns, aError)); + } + case 63: { // rondpoint:rondpoint_84bf_copie_enumerations + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_copie_enumerations, aGlobal, aArgs, "rondpoint_84bf_copie_enumerations: "_ns, aError)); + } + case 64: { // rondpoint:rondpoint_84bf_copie_carte + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_copie_carte, aGlobal, aArgs, "rondpoint_84bf_copie_carte: "_ns, aError)); + } + case 65: { // rondpoint:rondpoint_84bf_switcheroo + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(rondpoint_84bf_switcheroo, aGlobal, aArgs, "rondpoint_84bf_switcheroo: "_ns, aError)); + } + case 66: { // sprites:sprites_f59e_Sprite_new + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(sprites_f59e_Sprite_new, aGlobal, aArgs, "sprites_f59e_Sprite_new: "_ns, aError)); + } + case 67: { // sprites:sprites_f59e_Sprite_new_relative_to + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(sprites_f59e_Sprite_new_relative_to, aGlobal, aArgs, "sprites_f59e_Sprite_new_relative_to: "_ns, aError)); + } + case 68: { // sprites:sprites_f59e_Sprite_get_position + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSpritesSpritePointerType>>; + return Some(CallHandler::CallAsync(sprites_f59e_Sprite_get_position, aGlobal, aArgs, "sprites_f59e_Sprite_get_position: "_ns, aError)); + } + case 69: { // sprites:sprites_f59e_Sprite_move_to + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSpritesSpritePointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(sprites_f59e_Sprite_move_to, aGlobal, aArgs, "sprites_f59e_Sprite_move_to: "_ns, aError)); + } + case 70: { // sprites:sprites_f59e_Sprite_move_by + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSpritesSpritePointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(sprites_f59e_Sprite_move_by, aGlobal, aArgs, "sprites_f59e_Sprite_move_by: "_ns, aError)); + } + case 71: { // sprites:sprites_f59e_translate + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(sprites_f59e_translate, aGlobal, aArgs, "sprites_f59e_translate: "_ns, aError)); + } + case 72: { // todolist:todolist_9473_TodoList_new + using CallHandler = ScaffoldingCallHandler>; + return Some(CallHandler::CallAsync(todolist_9473_TodoList_new, aGlobal, aArgs, "todolist_9473_TodoList_new: "_ns, aError)); + } + case 73: { // todolist:todolist_9473_TodoList_add_item + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(todolist_9473_TodoList_add_item, aGlobal, aArgs, "todolist_9473_TodoList_add_item: "_ns, aError)); + } + case 74: { // todolist:todolist_9473_TodoList_add_entry + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(todolist_9473_TodoList_add_entry, aGlobal, aArgs, "todolist_9473_TodoList_add_entry: "_ns, aError)); + } + case 75: { // todolist:todolist_9473_TodoList_get_entries + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; + return Some(CallHandler::CallAsync(todolist_9473_TodoList_get_entries, aGlobal, aArgs, "todolist_9473_TodoList_get_entries: "_ns, aError)); + } + case 76: { // todolist:todolist_9473_TodoList_get_items + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; + return Some(CallHandler::CallAsync(todolist_9473_TodoList_get_items, aGlobal, aArgs, "todolist_9473_TodoList_get_items: "_ns, aError)); + } + case 77: { // todolist:todolist_9473_TodoList_add_entries + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(todolist_9473_TodoList_add_entries, aGlobal, aArgs, "todolist_9473_TodoList_add_entries: "_ns, aError)); + } + case 78: { // todolist:todolist_9473_TodoList_add_items + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(todolist_9473_TodoList_add_items, aGlobal, aArgs, "todolist_9473_TodoList_add_items: "_ns, aError)); + } + case 79: { // todolist:todolist_9473_TodoList_get_last_entry + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; + return Some(CallHandler::CallAsync(todolist_9473_TodoList_get_last_entry, aGlobal, aArgs, "todolist_9473_TodoList_get_last_entry: "_ns, aError)); + } + case 80: { // todolist:todolist_9473_TodoList_get_last + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; + return Some(CallHandler::CallAsync(todolist_9473_TodoList_get_last, aGlobal, aArgs, "todolist_9473_TodoList_get_last: "_ns, aError)); + } + case 81: { // todolist:todolist_9473_TodoList_get_first + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; + return Some(CallHandler::CallAsync(todolist_9473_TodoList_get_first, aGlobal, aArgs, "todolist_9473_TodoList_get_first: "_ns, aError)); + } + case 82: { // todolist:todolist_9473_TodoList_clear_item + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(todolist_9473_TodoList_clear_item, aGlobal, aArgs, "todolist_9473_TodoList_clear_item: "_ns, aError)); + } + case 83: { // todolist:todolist_9473_TodoList_make_default + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; + return Some(CallHandler::CallAsync(todolist_9473_TodoList_make_default, aGlobal, aArgs, "todolist_9473_TodoList_make_default: "_ns, aError)); + } + case 84: { // todolist:todolist_9473_get_default_list + using CallHandler = ScaffoldingCallHandler>; + return Some(CallHandler::CallAsync(todolist_9473_get_default_list, aGlobal, aArgs, "todolist_9473_get_default_list: "_ns, aError)); + } + case 85: { // todolist:todolist_9473_set_default_list + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; + return Some(CallHandler::CallAsync(todolist_9473_set_default_list, aGlobal, aArgs, "todolist_9473_set_default_list: "_ns, aError)); + } + case 86: { // todolist:todolist_9473_create_entry_with + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + return Some(CallHandler::CallAsync(todolist_9473_create_entry_with, aGlobal, aArgs, "todolist_9473_create_entry_with: "_ns, aError)); + } + } + return Nothing(); +} + +bool UniFFIFixturesCallSync(const GlobalObject& aGlobal, uint64_t aId, const Sequence& aArgs, RootedDictionary& aReturnValue, ErrorResult& aError) { + switch (aId) { + case 0: { // geometry:geometry_ba8c_gradient + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + CallHandler::CallSync(geometry_ba8c_gradient, aGlobal, aArgs, aReturnValue, "geometry_ba8c_gradient: "_ns, aError); + return true; + } + case 1: { // geometry:geometry_ba8c_intersection + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + CallHandler::CallSync(geometry_ba8c_intersection, aGlobal, aArgs, aReturnValue, "geometry_ba8c_intersection: "_ns, aError); + return true; + } + case 2: { // arithmetic:arithmetic_77d6_add + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + CallHandler::CallSync(arithmetic_77d6_add, aGlobal, aArgs, aReturnValue, "arithmetic_77d6_add: "_ns, aError); + return true; + } + case 3: { // arithmetic:arithmetic_77d6_sub + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + CallHandler::CallSync(arithmetic_77d6_sub, aGlobal, aArgs, aReturnValue, "arithmetic_77d6_sub: "_ns, aError); + return true; + } + case 4: { // arithmetic:arithmetic_77d6_div + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + CallHandler::CallSync(arithmetic_77d6_div, aGlobal, aArgs, aReturnValue, "arithmetic_77d6_div: "_ns, aError); + return true; + } + case 5: { // arithmetic:arithmetic_77d6_equal + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + CallHandler::CallSync(arithmetic_77d6_equal, aGlobal, aArgs, aReturnValue, "arithmetic_77d6_equal: "_ns, aError); + return true; + } + case 6: { // rondpoint:rondpoint_84bf_Retourneur_new + using CallHandler = ScaffoldingCallHandler>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_new, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_new: "_ns, aError); + return true; + } + case 7: { // rondpoint:rondpoint_84bf_Retourneur_identique_i8 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_i8, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_i8: "_ns, aError); + return true; + } + case 8: { // rondpoint:rondpoint_84bf_Retourneur_identique_u8 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_u8, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_u8: "_ns, aError); + return true; + } + case 9: { // rondpoint:rondpoint_84bf_Retourneur_identique_i16 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_i16, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_i16: "_ns, aError); + return true; + } + case 10: { // rondpoint:rondpoint_84bf_Retourneur_identique_u16 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_u16, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_u16: "_ns, aError); + return true; + } + case 11: { // rondpoint:rondpoint_84bf_Retourneur_identique_i32 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_i32, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_i32: "_ns, aError); + return true; + } + case 12: { // rondpoint:rondpoint_84bf_Retourneur_identique_u32 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_u32, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_u32: "_ns, aError); + return true; + } + case 13: { // rondpoint:rondpoint_84bf_Retourneur_identique_i64 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_i64, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_i64: "_ns, aError); + return true; + } + case 14: { // rondpoint:rondpoint_84bf_Retourneur_identique_u64 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_u64, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_u64: "_ns, aError); + return true; + } + case 15: { // rondpoint:rondpoint_84bf_Retourneur_identique_float + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_float, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_float: "_ns, aError); + return true; + } + case 16: { // rondpoint:rondpoint_84bf_Retourneur_identique_double + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_double, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_double: "_ns, aError); + return true; + } + case 17: { // rondpoint:rondpoint_84bf_Retourneur_identique_boolean + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_boolean, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_boolean: "_ns, aError); + return true; + } + case 18: { // rondpoint:rondpoint_84bf_Retourneur_identique_string + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_string, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_string: "_ns, aError); + return true; + } + case 19: { // rondpoint:rondpoint_84bf_Retourneur_identique_nombres_signes + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_nombres_signes, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_nombres_signes: "_ns, aError); + return true; + } + case 20: { // rondpoint:rondpoint_84bf_Retourneur_identique_nombres + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_nombres, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_nombres: "_ns, aError); + return true; + } + case 21: { // rondpoint:rondpoint_84bf_Retourneur_identique_optionneur_dictionnaire + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointRetourneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Retourneur_identique_optionneur_dictionnaire, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Retourneur_identique_optionneur_dictionnaire: "_ns, aError); + return true; + } + case 22: { // rondpoint:rondpoint_84bf_Stringifier_new + using CallHandler = ScaffoldingCallHandler>; + CallHandler::CallSync(rondpoint_84bf_Stringifier_new, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Stringifier_new: "_ns, aError); + return true; + } + case 23: { // rondpoint:rondpoint_84bf_Stringifier_well_known_string + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Stringifier_well_known_string, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Stringifier_well_known_string: "_ns, aError); + return true; + } + case 24: { // rondpoint:rondpoint_84bf_Stringifier_to_string_i8 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Stringifier_to_string_i8, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Stringifier_to_string_i8: "_ns, aError); + return true; + } + case 25: { // rondpoint:rondpoint_84bf_Stringifier_to_string_u8 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Stringifier_to_string_u8, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Stringifier_to_string_u8: "_ns, aError); + return true; + } + case 26: { // rondpoint:rondpoint_84bf_Stringifier_to_string_i16 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Stringifier_to_string_i16, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Stringifier_to_string_i16: "_ns, aError); + return true; + } + case 27: { // rondpoint:rondpoint_84bf_Stringifier_to_string_u16 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Stringifier_to_string_u16, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Stringifier_to_string_u16: "_ns, aError); + return true; + } + case 28: { // rondpoint:rondpoint_84bf_Stringifier_to_string_i32 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Stringifier_to_string_i32, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Stringifier_to_string_i32: "_ns, aError); + return true; + } + case 29: { // rondpoint:rondpoint_84bf_Stringifier_to_string_u32 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Stringifier_to_string_u32, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Stringifier_to_string_u32: "_ns, aError); + return true; + } + case 30: { // rondpoint:rondpoint_84bf_Stringifier_to_string_i64 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Stringifier_to_string_i64, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Stringifier_to_string_i64: "_ns, aError); + return true; + } + case 31: { // rondpoint:rondpoint_84bf_Stringifier_to_string_u64 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Stringifier_to_string_u64, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Stringifier_to_string_u64: "_ns, aError); + return true; + } + case 32: { // rondpoint:rondpoint_84bf_Stringifier_to_string_float + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Stringifier_to_string_float, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Stringifier_to_string_float: "_ns, aError); + return true; + } + case 33: { // rondpoint:rondpoint_84bf_Stringifier_to_string_double + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Stringifier_to_string_double, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Stringifier_to_string_double: "_ns, aError); + return true; + } + case 34: { // rondpoint:rondpoint_84bf_Stringifier_to_string_boolean + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointStringifierPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Stringifier_to_string_boolean, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Stringifier_to_string_boolean: "_ns, aError); + return true; + } + case 35: { // rondpoint:rondpoint_84bf_Optionneur_new + using CallHandler = ScaffoldingCallHandler>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_new, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_new: "_ns, aError); + return true; + } + case 36: { // rondpoint:rondpoint_84bf_Optionneur_sinon_boolean + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_boolean, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_boolean: "_ns, aError); + return true; + } + case 37: { // rondpoint:rondpoint_84bf_Optionneur_sinon_string + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_string, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_string: "_ns, aError); + return true; + } + case 38: { // rondpoint:rondpoint_84bf_Optionneur_sinon_sequence + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_sequence, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_sequence: "_ns, aError); + return true; + } + case 39: { // rondpoint:rondpoint_84bf_Optionneur_sinon_null + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_null, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_null: "_ns, aError); + return true; + } + case 40: { // rondpoint:rondpoint_84bf_Optionneur_sinon_zero + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_zero, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_zero: "_ns, aError); + return true; + } + case 41: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u8_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_u8_dec, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_u8_dec: "_ns, aError); + return true; + } + case 42: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i8_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_i8_dec, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_i8_dec: "_ns, aError); + return true; + } + case 43: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u16_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_u16_dec, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_u16_dec: "_ns, aError); + return true; + } + case 44: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i16_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_i16_dec, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_i16_dec: "_ns, aError); + return true; + } + case 45: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u32_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_u32_dec, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_u32_dec: "_ns, aError); + return true; + } + case 46: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i32_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_i32_dec, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_i32_dec: "_ns, aError); + return true; + } + case 47: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u64_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_u64_dec, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_u64_dec: "_ns, aError); + return true; + } + case 48: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i64_dec + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_i64_dec, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_i64_dec: "_ns, aError); + return true; + } + case 49: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u8_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_u8_hex, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_u8_hex: "_ns, aError); + return true; + } + case 50: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i8_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_i8_hex, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_i8_hex: "_ns, aError); + return true; + } + case 51: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u16_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_u16_hex, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_u16_hex: "_ns, aError); + return true; + } + case 52: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i16_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_i16_hex, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_i16_hex: "_ns, aError); + return true; + } + case 53: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u32_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_u32_hex, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_u32_hex: "_ns, aError); + return true; + } + case 54: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i32_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_i32_hex, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_i32_hex: "_ns, aError); + return true; + } + case 55: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u64_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_u64_hex, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_u64_hex: "_ns, aError); + return true; + } + case 56: { // rondpoint:rondpoint_84bf_Optionneur_sinon_i64_hex + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_i64_hex, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_i64_hex: "_ns, aError); + return true; + } + case 57: { // rondpoint:rondpoint_84bf_Optionneur_sinon_u32_oct + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_u32_oct, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_u32_oct: "_ns, aError); + return true; + } + case 58: { // rondpoint:rondpoint_84bf_Optionneur_sinon_f32 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_f32, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_f32: "_ns, aError); + return true; + } + case 59: { // rondpoint:rondpoint_84bf_Optionneur_sinon_f64 + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_f64, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_f64: "_ns, aError); + return true; + } + case 60: { // rondpoint:rondpoint_84bf_Optionneur_sinon_enum + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kRondpointOptionneurPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_Optionneur_sinon_enum, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_Optionneur_sinon_enum: "_ns, aError); + return true; + } + case 61: { // rondpoint:rondpoint_84bf_copie_dictionnaire + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_copie_dictionnaire, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_copie_dictionnaire: "_ns, aError); + return true; + } + case 62: { // rondpoint:rondpoint_84bf_copie_enumeration + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_copie_enumeration, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_copie_enumeration: "_ns, aError); + return true; + } + case 63: { // rondpoint:rondpoint_84bf_copie_enumerations + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_copie_enumerations, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_copie_enumerations: "_ns, aError); + return true; + } + case 64: { // rondpoint:rondpoint_84bf_copie_carte + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_copie_carte, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_copie_carte: "_ns, aError); + return true; + } + case 65: { // rondpoint:rondpoint_84bf_switcheroo + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + CallHandler::CallSync(rondpoint_84bf_switcheroo, aGlobal, aArgs, aReturnValue, "rondpoint_84bf_switcheroo: "_ns, aError); + return true; + } + case 66: { // sprites:sprites_f59e_Sprite_new + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + CallHandler::CallSync(sprites_f59e_Sprite_new, aGlobal, aArgs, aReturnValue, "sprites_f59e_Sprite_new: "_ns, aError); + return true; + } + case 67: { // sprites:sprites_f59e_Sprite_new_relative_to + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + CallHandler::CallSync(sprites_f59e_Sprite_new_relative_to, aGlobal, aArgs, aReturnValue, "sprites_f59e_Sprite_new_relative_to: "_ns, aError); + return true; + } + case 68: { // sprites:sprites_f59e_Sprite_get_position + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSpritesSpritePointerType>>; + CallHandler::CallSync(sprites_f59e_Sprite_get_position, aGlobal, aArgs, aReturnValue, "sprites_f59e_Sprite_get_position: "_ns, aError); + return true; + } + case 69: { // sprites:sprites_f59e_Sprite_move_to + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSpritesSpritePointerType>, ScaffoldingConverter>; + CallHandler::CallSync(sprites_f59e_Sprite_move_to, aGlobal, aArgs, aReturnValue, "sprites_f59e_Sprite_move_to: "_ns, aError); + return true; + } + case 70: { // sprites:sprites_f59e_Sprite_move_by + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kSpritesSpritePointerType>, ScaffoldingConverter>; + CallHandler::CallSync(sprites_f59e_Sprite_move_by, aGlobal, aArgs, aReturnValue, "sprites_f59e_Sprite_move_by: "_ns, aError); + return true; + } + case 71: { // sprites:sprites_f59e_translate + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter, ScaffoldingConverter>; + CallHandler::CallSync(sprites_f59e_translate, aGlobal, aArgs, aReturnValue, "sprites_f59e_translate: "_ns, aError); + return true; + } + case 72: { // todolist:todolist_9473_TodoList_new + using CallHandler = ScaffoldingCallHandler>; + CallHandler::CallSync(todolist_9473_TodoList_new, aGlobal, aArgs, aReturnValue, "todolist_9473_TodoList_new: "_ns, aError); + return true; + } + case 73: { // todolist:todolist_9473_TodoList_add_item + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(todolist_9473_TodoList_add_item, aGlobal, aArgs, aReturnValue, "todolist_9473_TodoList_add_item: "_ns, aError); + return true; + } + case 74: { // todolist:todolist_9473_TodoList_add_entry + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(todolist_9473_TodoList_add_entry, aGlobal, aArgs, aReturnValue, "todolist_9473_TodoList_add_entry: "_ns, aError); + return true; + } + case 75: { // todolist:todolist_9473_TodoList_get_entries + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; + CallHandler::CallSync(todolist_9473_TodoList_get_entries, aGlobal, aArgs, aReturnValue, "todolist_9473_TodoList_get_entries: "_ns, aError); + return true; + } + case 76: { // todolist:todolist_9473_TodoList_get_items + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; + CallHandler::CallSync(todolist_9473_TodoList_get_items, aGlobal, aArgs, aReturnValue, "todolist_9473_TodoList_get_items: "_ns, aError); + return true; + } + case 77: { // todolist:todolist_9473_TodoList_add_entries + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(todolist_9473_TodoList_add_entries, aGlobal, aArgs, aReturnValue, "todolist_9473_TodoList_add_entries: "_ns, aError); + return true; + } + case 78: { // todolist:todolist_9473_TodoList_add_items + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(todolist_9473_TodoList_add_items, aGlobal, aArgs, aReturnValue, "todolist_9473_TodoList_add_items: "_ns, aError); + return true; + } + case 79: { // todolist:todolist_9473_TodoList_get_last_entry + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; + CallHandler::CallSync(todolist_9473_TodoList_get_last_entry, aGlobal, aArgs, aReturnValue, "todolist_9473_TodoList_get_last_entry: "_ns, aError); + return true; + } + case 80: { // todolist:todolist_9473_TodoList_get_last + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; + CallHandler::CallSync(todolist_9473_TodoList_get_last, aGlobal, aArgs, aReturnValue, "todolist_9473_TodoList_get_last: "_ns, aError); + return true; + } + case 81: { // todolist:todolist_9473_TodoList_get_first + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; + CallHandler::CallSync(todolist_9473_TodoList_get_first, aGlobal, aArgs, aReturnValue, "todolist_9473_TodoList_get_first: "_ns, aError); + return true; + } + case 82: { // todolist:todolist_9473_TodoList_clear_item + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>, ScaffoldingConverter>; + CallHandler::CallSync(todolist_9473_TodoList_clear_item, aGlobal, aArgs, aReturnValue, "todolist_9473_TodoList_clear_item: "_ns, aError); + return true; + } + case 83: { // todolist:todolist_9473_TodoList_make_default + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; + CallHandler::CallSync(todolist_9473_TodoList_make_default, aGlobal, aArgs, aReturnValue, "todolist_9473_TodoList_make_default: "_ns, aError); + return true; + } + case 84: { // todolist:todolist_9473_get_default_list + using CallHandler = ScaffoldingCallHandler>; + CallHandler::CallSync(todolist_9473_get_default_list, aGlobal, aArgs, aReturnValue, "todolist_9473_get_default_list: "_ns, aError); + return true; + } + case 85: { // todolist:todolist_9473_set_default_list + using CallHandler = ScaffoldingCallHandler, ScaffoldingObjectConverter<&kTodolistTodoListPointerType>>; + CallHandler::CallSync(todolist_9473_set_default_list, aGlobal, aArgs, aReturnValue, "todolist_9473_set_default_list: "_ns, aError); + return true; + } + case 86: { // todolist:todolist_9473_create_entry_with + using CallHandler = ScaffoldingCallHandler, ScaffoldingConverter>; + CallHandler::CallSync(todolist_9473_create_entry_with, aGlobal, aArgs, aReturnValue, "todolist_9473_create_entry_with: "_ns, aError); + return true; + } + } + return false; +} + +Maybe> UniFFIFixturesReadPointer(const GlobalObject& aGlobal, uint64_t aId, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) { + const UniFFIPointerType* type; + switch (aId) { + case 0: { // rondpoint:Retourneur + type = &kRondpointRetourneurPointerType; + break; + } + case 1: { // rondpoint:Stringifier + type = &kRondpointStringifierPointerType; + break; + } + case 2: { // rondpoint:Optionneur + type = &kRondpointOptionneurPointerType; + break; + } + case 3: { // sprites:Sprite + type = &kSpritesSpritePointerType; + break; + } + case 4: { // todolist:TodoList + type = &kTodolistTodoListPointerType; + break; + } + default: + return Nothing(); + } + return Some(UniFFIPointer::Read(aArrayBuff, aPosition, type, aError)); +} + +bool UniFFIFixturesWritePointer(const GlobalObject& aGlobal, uint64_t aId, const UniFFIPointer& aPtr, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) { + const UniFFIPointerType* type; + switch (aId) { + case 0: { // rondpoint:Retourneur + type = &kRondpointRetourneurPointerType; + break; + } + case 1: { // rondpoint:Stringifier + type = &kRondpointStringifierPointerType; + break; + } + case 2: { // rondpoint:Optionneur + type = &kRondpointOptionneurPointerType; + break; + } + case 3: { // sprites:Sprite + type = &kSpritesSpritePointerType; + break; + } + case 4: { // todolist:TodoList + type = &kTodolistTodoListPointerType; + break; + } + default: + return false; + } + aPtr.Write(aArrayBuff, aPosition, type, aError); + return true; +} + +} // namespace mozilla::uniffi diff --git a/toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp b/toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp new file mode 100644 index 000000000000..ca19440a8570 --- /dev/null +++ b/toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp @@ -0,0 +1,57 @@ +// Generated by uniffi-bindgen-gecko-js. DO NOT EDIT. + +#include "nsString.h" +#include "nsPrintfCString.h" +#include "mozilla/Maybe.h" +#include "mozilla/dom/UniFFIScaffolding.h" +#include "mozilla/dom/ScaffoldingCall.h" + +namespace mozilla::uniffi { + +using dom::ArrayBuffer; +using dom::GlobalObject; +using dom::RootedDictionary; +using dom::Promise; +using dom::ScaffoldingType; +using dom::Sequence; +using dom::UniFFIPointer; +using dom::UniFFIScaffoldingCallResult; + +// Define scaffolding functions from UniFFI +extern "C" { +} + +// Define pointer types + +Maybe> UniFFICallAsync(const GlobalObject& aGlobal, uint64_t aId, const Sequence& aArgs, ErrorResult& aError) { + switch (aId) { + } + return Nothing(); +} + +bool UniFFICallSync(const GlobalObject& aGlobal, uint64_t aId, const Sequence& aArgs, RootedDictionary& aReturnValue, ErrorResult& aError) { + switch (aId) { + } + return false; +} + +Maybe> UniFFIReadPointer(const GlobalObject& aGlobal, uint64_t aId, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) { + const UniFFIPointerType* type; + switch (aId) { + default: + return Nothing(); + } + return Some(UniFFIPointer::Read(aArrayBuff, aPosition, type, aError)); +} + +bool UniFFIWritePointer(const GlobalObject& aGlobal, uint64_t aId, const UniFFIPointer& aPtr, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) { + const UniFFIPointerType* type; + switch (aId) { + default: + return false; + } + aPtr.Write(aArrayBuff, aPosition, type, aError); + return true; +} + +} // namespace mozilla::uniffi diff --git a/toolkit/components/uniffi-js/UniFFIPointer.cpp b/toolkit/components/uniffi-js/UniFFIPointer.cpp new file mode 100644 index 000000000000..9a204aac5de8 --- /dev/null +++ b/toolkit/components/uniffi-js/UniFFIPointer.cpp @@ -0,0 +1,112 @@ +/* -*- 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 "mozilla/EndianUtils.h" +#include "mozilla/dom/UniFFIPointer.h" +#include "mozilla/dom/UniFFIBinding.h" +#include "mozilla/Logging.h" +#include "UniFFIRust.h" + +static mozilla::LazyLogModule sUniFFIPointerLogger("uniffi_logger"); + +namespace mozilla::dom { +using uniffi::RUST_CALL_SUCCESS; +using uniffi::RustCallStatus; +using uniffi::UniFFIPointerType; + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(UniFFIPointer) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(UniFFIPointer) +NS_IMPL_CYCLE_COLLECTING_RELEASE(UniFFIPointer) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(UniFFIPointer) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +// Static function +already_AddRefed UniFFIPointer::Create( + void* aPtr, const UniFFIPointerType* aType) { + RefPtr uniFFIPointer = new UniFFIPointer(aPtr, aType); + return uniFFIPointer.forget(); +} + +already_AddRefed UniFFIPointer::Read( + const ArrayBuffer& aArrayBuff, uint32_t aPosition, + const UniFFIPointerType* aType, ErrorResult& aError) { + MOZ_LOG(sUniFFIPointerLogger, LogLevel::Info, + ("[UniFFI] Reading Pointer from buffer")); + aArrayBuff.ComputeState(); + + CheckedUint32 position = aPosition; + CheckedUint32 end = position + 8; + if (!end.isValid() || end.value() > aArrayBuff.Length()) { + aError.ThrowRangeError("position is out of range"); + return nullptr; + } + // in Rust and Write(), a pointer is converted to a void* then written as u64 + // BigEndian we do the reverse here + uint8_t* data_ptr = aArrayBuff.Data() + + aPosition; // Pointer arithmetic, move by position bytes + void* ptr = (void*)mozilla::BigEndian::readUint64(data_ptr); + return UniFFIPointer::Create(ptr, aType); +} + +void UniFFIPointer::Write(const ArrayBuffer& aArrayBuff, uint32_t aPosition, + const UniFFIPointerType* aType, + ErrorResult& aError) const { + if (!this->IsSamePtrType(aType)) { + aError.ThrowUnknownError(nsPrintfCString( + "Attempt to write pointer with wrong type: %s (expected: %s)", + aType->typeName.get(), this->mType->typeName.get())); + return; + } + MOZ_LOG(sUniFFIPointerLogger, LogLevel::Info, + ("[UniFFI] Writing Pointer to buffer")); + aArrayBuff.ComputeState(); + CheckedUint32 position = aPosition; + CheckedUint32 end = position + 8; + if (!end.isValid() || end.value() > aArrayBuff.Length()) { + aError.ThrowRangeError("position is out of range"); + return; + } + // in Rust and Read(), a u64 is read as BigEndian and then converted to a + // pointer we do the reverse here + uint8_t* data_ptr = aArrayBuff.Data() + + aPosition; // Pointer arithmetic, move by position bytes + mozilla::BigEndian::writeUint64(data_ptr, (uint64_t)GetPtr()); +} + +UniFFIPointer::UniFFIPointer(void* aPtr, const UniFFIPointerType* aType) { + mPtr = aPtr; + mType = aType; +} + +JSObject* UniFFIPointer::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) { + return dom::UniFFIPointer_Binding::Wrap(aCx, this, aGivenProto); +} + +void* UniFFIPointer::GetPtr() const { + MOZ_LOG(sUniFFIPointerLogger, LogLevel::Info, + ("[UniFFI] Getting raw pointer")); + return this->mPtr; +} + +bool UniFFIPointer::IsSamePtrType(const UniFFIPointerType* aType) const { + return this->mType == aType; +} + +UniFFIPointer::~UniFFIPointer() { + MOZ_LOG(sUniFFIPointerLogger, LogLevel::Info, + ("[UniFFI] Destroying pointer")); + RustCallStatus status{}; + this->mType->destructor(this->mPtr, &status); + MOZ_DIAGNOSTIC_ASSERT(status.code == RUST_CALL_SUCCESS, + "UniFFI destructor call returned a non-success result"); +} + +} // namespace mozilla::dom diff --git a/toolkit/components/uniffi-js/UniFFIPointer.h b/toolkit/components/uniffi-js/UniFFIPointer.h new file mode 100644 index 000000000000..9a824d81ede4 --- /dev/null +++ b/toolkit/components/uniffi-js/UniFFIPointer.h @@ -0,0 +1,67 @@ +/* -*- 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_UniFFIPointer_h +#define mozilla_dom_UniFFIPointer_h + +#include "nsISupports.h" +#include "nsWrapperCache.h" +#include "nsString.h" +#include "mozilla/dom/UniFFIPointerType.h" + +namespace mozilla::dom { + +class UniFFIPointer final : public nsISupports, public nsWrapperCache { + public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(UniFFIPointer) + + static already_AddRefed Create( + void* aPtr, const uniffi::UniFFIPointerType* aType); + static already_AddRefed Read( + const ArrayBuffer& aArrayBuff, uint32_t aPosition, + const uniffi::UniFFIPointerType* aType, ErrorResult& aError); + void Write(const ArrayBuffer& aArrayBuff, uint32_t aPosition, + const uniffi::UniFFIPointerType* aType, ErrorResult& aError) const; + + UniFFIPointer(void* aPtr, const uniffi::UniFFIPointerType* aType); + + JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + nsISupports* GetParentObject() { return nullptr; } + + /** + * returns the raw pointer `UniFFIPointer` holds + * This is safe because: + * - The pointer was allocated in Rust as a reference counted `Arc` + * - Rust cloned the pointer without destructing it when passed into C++ + * - Eventually, when the destructor of `UniFFIPointer` runs, we return + * ownership to Rust, which then decrements the count and deallocates the + * memory the pointer points to. + */ + void* GetPtr() const; + + /** + * Returns true if the pointer type `this` holds is the same as the argument + * it does so using pointer comparison, as there is **exactly** one static + * `UniFFIPointerType` per type exposed in the UniFFI interface + */ + bool IsSamePtrType(const uniffi::UniFFIPointerType* type) const; + + private: + const uniffi::UniFFIPointerType* mType; + void* mPtr; + + protected: + /** + * Destructs the `UniFFIPointer`, making sure to give back ownership of the + * raw pointer back to Rust, which deallocates the pointer + */ + ~UniFFIPointer(); +}; +} // namespace mozilla::dom + +#endif /* mozilla_dom_UniFFIPointer_h */ diff --git a/toolkit/components/uniffi-js/UniFFIPointerType.h b/toolkit/components/uniffi-js/UniFFIPointerType.h new file mode 100644 index 000000000000..7236e50cb79c --- /dev/null +++ b/toolkit/components/uniffi-js/UniFFIPointerType.h @@ -0,0 +1,29 @@ +/* -*- 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_UniFFIPointerType_h +#define mozilla_UniFFIPointerType_h + +#include "nsISupports.h" +#include "nsWrapperCache.h" +#include "nsLiteralString.h" +#include "UniFFIRust.h" + +namespace mozilla::uniffi { + +/** + * UniFFIPointerType represents of UniFFI allocated pointers. + * Each UniFFIPointer will have a UniFFIPointerType, which will be a statically + * allocated type per object exposed by the UniFFI interface + **/ +struct UniFFIPointerType { + nsLiteralCString typeName; + // The Rust destructor for the pointer, this gives back ownership to Rust + void (*destructor)(void*, RustCallStatus*); +}; +} // namespace mozilla::uniffi + +#endif /* mozilla_UniFFIPointerType_h */ diff --git a/toolkit/components/uniffi-js/UniFFIRust.h b/toolkit/components/uniffi-js/UniFFIRust.h new file mode 100644 index 000000000000..b7bffbe6bdf9 --- /dev/null +++ b/toolkit/components/uniffi-js/UniFFIRust.h @@ -0,0 +1,40 @@ +/* -*- 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_UniFFIRust_h +#define mozilla_UniFFIRust_h + +#include + +namespace mozilla::uniffi { + +// Low-level Rust structs for UniFFI + +// RustCallStatus.code values +constexpr int8_t RUST_CALL_SUCCESS = 0; +constexpr int8_t RUST_CALL_ERROR = 1; +constexpr int8_t RUST_CALL_INTERNAL_ERROR = 2; + +// structs/functions from UniFFI +extern "C" { +struct RustBuffer { + int32_t capacity; + int32_t len; + uint8_t* data; +}; + +struct RustCallStatus { + int8_t code; + RustBuffer error_buf; +}; + +RustBuffer uniffi_rustbuffer_alloc(int32_t size, RustCallStatus* call_status); +void uniffi_rustbuffer_free(RustBuffer buf, RustCallStatus* call_status); +} + +} // namespace mozilla::uniffi + +#endif /* mozilla_UniFFIRust_h */ diff --git a/toolkit/components/uniffi-js/UniFFIScaffolding.cpp b/toolkit/components/uniffi-js/UniFFIScaffolding.cpp new file mode 100644 index 000000000000..6be1693faf7e --- /dev/null +++ b/toolkit/components/uniffi-js/UniFFIScaffolding.cpp @@ -0,0 +1,147 @@ +/* -*- 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 +#include "nsError.h" +#include "nsString.h" +#include "nsPrintfCString.h" +#include "mozilla/Maybe.h" +#include "mozilla/dom/UniFFIScaffolding.h" + +// This file implements the UniFFI WebIDL interface by leveraging the generate +// 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::GlobalObject; +using mozilla::dom::Promise; +using mozilla::dom::RootedDictionary; +using mozilla::dom::ScaffoldingType; +using mozilla::dom::Sequence; +using mozilla::dom::UniFFIPointer; +using mozilla::dom::UniFFIScaffoldingCallResult; + +namespace mozilla::uniffi { + +// Prototypes for the generated functions +Maybe> UniFFICallAsync( + const GlobalObject& aGlobal, uint64_t aId, + const Sequence& aArgs, ErrorResult& aError); +bool UniFFICallSync(const GlobalObject& aGlobal, uint64_t aId, + const Sequence& aArgs, + RootedDictionary& aReturnValue, + ErrorResult& aError); +Maybe> UniFFIReadPointer( + const GlobalObject& aGlobal, uint64_t aId, const ArrayBuffer& aArrayBuff, + long aPosition, ErrorResult& aError); +bool UniFFIWritePointer(const GlobalObject& aGlobal, uint64_t aId, + const UniFFIPointer& aPtr, + const ArrayBuffer& aArrayBuff, long aPosition, + ErrorResult& aError); + +#ifdef MOZ_UNIFFI_FIXTURES +Maybe> UniFFIFixturesCallAsync( + const GlobalObject& aGlobal, uint64_t aId, + const Sequence& aArgs, ErrorResult& aError); +bool UniFFIFixturesCallSync( + const GlobalObject& aGlobal, uint64_t aId, + const Sequence& aArgs, + RootedDictionary& aReturnValue, + ErrorResult& aError); +Maybe> UniFFIFixturesReadPointer( + const GlobalObject& aGlobal, uint64_t aId, const ArrayBuffer& aArrayBuff, + long aPosition, ErrorResult& aError); +bool UniFFIFixturesWritePointer(const GlobalObject& aGlobal, uint64_t aId, + const UniFFIPointer& aPtr, + const ArrayBuffer& aArrayBuff, long aPosition, + ErrorResult& aError); +#endif +} // namespace mozilla::uniffi + +namespace mozilla::dom { + +// Implement the interface using the generated functions + +already_AddRefed UniFFIScaffolding::CallAsync( + const GlobalObject& aGlobal, uint64_t aId, + const Sequence& aArgs, ErrorResult& aError) { + Maybe> firstTry = + uniffi::UniFFICallAsync(aGlobal, aId, aArgs, aError); + if (firstTry.isSome()) { + return firstTry.extract(); + } +#ifdef MOZ_UNIFFI_FIXTURES + Maybe> secondTry = + uniffi::UniFFIFixturesCallAsync(aGlobal, aId, aArgs, aError); + if (secondTry.isSome()) { + return secondTry.extract(); + } +#endif + + aError.ThrowUnknownError( + nsPrintfCString("Unknown function id: %" PRIu64, aId)); + return nullptr; +} + +void UniFFIScaffolding::CallSync( + const GlobalObject& aGlobal, uint64_t aId, + const Sequence& aArgs, + RootedDictionary& aReturnValue, + ErrorResult& aError) { + if (uniffi::UniFFICallSync(aGlobal, aId, aArgs, aReturnValue, aError)) { + return; + } +#ifdef MOZ_UNIFFI_FIXTURES + if (uniffi::UniFFIFixturesCallSync(aGlobal, aId, aArgs, aReturnValue, + aError)) { + return; + } +#endif + + aError.ThrowUnknownError( + nsPrintfCString("Unknown function id: %" PRIu64, aId)); +} + +already_AddRefed UniFFIScaffolding::ReadPointer( + const GlobalObject& aGlobal, uint64_t aId, const ArrayBuffer& aArrayBuff, + long aPosition, ErrorResult& aError) { + Maybe> firstTry = + uniffi::UniFFIReadPointer(aGlobal, aId, aArrayBuff, aPosition, aError); + if (firstTry.isSome()) { + return firstTry.extract(); + } +#ifdef MOZ_UNIFFI_FIXTURES + Maybe> secondTry = + uniffi::UniFFIFixturesReadPointer(aGlobal, aId, aArrayBuff, aPosition, + aError); + if (secondTry.isSome()) { + return secondTry.extract(); + } +#endif + + aError.ThrowUnknownError(nsPrintfCString("Unknown object id: %" PRIu64, aId)); + return nullptr; +} + +void UniFFIScaffolding::WritePointer(const GlobalObject& aGlobal, uint64_t aId, + const UniFFIPointer& aPtr, + const ArrayBuffer& aArrayBuff, + long aPosition, ErrorResult& aError) { + if (uniffi::UniFFIWritePointer(aGlobal, aId, aPtr, aArrayBuff, aPosition, + aError)) { + return; + } +#ifdef MOZ_UNIFFI_FIXTURES + if (uniffi::UniFFIFixturesWritePointer(aGlobal, aId, aPtr, aArrayBuff, + aPosition, aError)) { + return; + } +#endif + + aError.ThrowUnknownError(nsPrintfCString("Unknown object id: %" PRIu64, aId)); +} + +} // namespace mozilla::dom diff --git a/toolkit/components/uniffi-js/UniFFIScaffolding.h b/toolkit/components/uniffi-js/UniFFIScaffolding.h new file mode 100644 index 000000000000..7b0270cd77a2 --- /dev/null +++ b/toolkit/components/uniffi-js/UniFFIScaffolding.h @@ -0,0 +1,42 @@ +/* -*- 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_UniFFI_h +#define mozilla_dom_UniFFI_h + +#include "mozilla/dom/RootedDictionary.h" +#include "mozilla/dom/UniFFIBinding.h" + +namespace mozilla::dom { + +using ScaffoldingType = OwningDoubleOrArrayBufferOrUniFFIPointer; + +// Handle functions defined in UniFFIScaffolding.webidl +class UniFFIScaffolding { + public: + static already_AddRefed CallAsync( + const GlobalObject& aUniFFIGlobal, uint64_t aId, + const Sequence& aArgs, ErrorResult& aUniFFIErrorResult); + + static void CallSync( + const GlobalObject& aUniFFIGlobal, uint64_t aId, + const Sequence& aArgs, + RootedDictionary& aUniFFIReturnValue, + ErrorResult& aUniFFIErrorResult); + + static already_AddRefed ReadPointer( + const GlobalObject& aUniFFIGlobal, uint64_t aId, + const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError); + + static void WritePointer(const GlobalObject& aUniFFIGlobal, uint64_t aId, + const UniFFIPointer& aPtr, + const ArrayBuffer& aArrayBuff, long aPosition, + ErrorResult& aError); +}; + +} // namespace mozilla::dom + +#endif /* mozilla_dom_UniFFI_h */ diff --git a/toolkit/components/uniffi-js/moz.build b/toolkit/components/uniffi-js/moz.build new file mode 100644 index 000000000000..b1311a93e424 --- /dev/null +++ b/toolkit/components/uniffi-js/moz.build @@ -0,0 +1,29 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +FINAL_LIBRARY = "xul" + +UNIFIED_SOURCES += [ + "OwnedRustBuffer.cpp", + "UniFFIGeneratedScaffolding.cpp", + "UniFFIPointer.cpp", + "UniFFIScaffolding.cpp", +] + +if CONFIG["MOZ_UNIFFI_FIXTURES"]: + UNIFIED_SOURCES += [ + "UniFFIFixtureScaffolding.cpp", + ] + +EXPORTS.mozilla.dom += [ + "OwnedRustBuffer.h", + "ScaffoldingCall.h", + "ScaffoldingConverter.h", + "UniFFIPointer.h", + "UniFFIPointerType.h", + "UniFFIRust.h", + "UniFFIScaffolding.h", +] diff --git a/tools/lint/license.yml b/tools/lint/license.yml index 2f48282c2fc1..fdc088146e7a 100644 --- a/tools/lint/license.yml +++ b/tools/lint/license.yml @@ -60,6 +60,8 @@ license: - toolkit/components/reputationservice/chromium/chrome/common/safe_browsing/csd.pb.h - toolkit/mozapps/update/updater/crctable.h - tools/lint/eslint/eslint-plugin-mozilla/lib/configs + # template fragments used to generate .js sources. + - toolkit/components/uniffi-bindgen-gecko-js/src/templates/js # By design - tools/lint/test/ extensions: diff --git a/tools/rewriting/Generated.txt b/tools/rewriting/Generated.txt index 1865e4ac32c9..88250c4ea984 100644 --- a/tools/rewriting/Generated.txt +++ b/tools/rewriting/Generated.txt @@ -9,3 +9,5 @@ node_modules/ intl/components/src/UnicodeScriptCodes.h intl/unicharutil/util/nsSpecialCasingData.cpp intl/unicharutil/util/nsUnicodePropertyData.cpp +toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp +toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp