Bug 1788306: UniFFI callback interfaces, r=nika

Started callback interface functionality to UniFFI.  Currently this only
supports the async fire-and-forget use case, where Rust queues a JS
function to run, but doesn't wait (or `await`) for the response.

The basic system is:

  - The JS code registers a callback interface handler with the C++
    code.  This handler is responsible for the specifics of invoking the
    callback.
  - The C++ code defines a function to call a JS handler.  Once the JS
    handler registers itself with C++, the C++ registers it's function
    with Rust.
  - The C++ code queues the call to the JS main thread.
  - Because of how UniFFI handles callback interfaces, the C++ code can
    be "dumb".  UniFFI sends a object id, method id, and RustBuffer
    encoding all arguments.  This means C++ doesn't need to care about
    the specific arguments, they get unpacked by JS.

I tried to keep the generated code as simple as possible by moving the
complexity to static code.  For JS this meant writing a generic
`UniFFICallbackHandler` class in the static code that the generated code
constructs.  For C++ this meant the generated code defines a
`UniFFIGetCallbackInterfaceInfo` function that returns a struct with all
the data specific to a callback interface (it's name, the UniFFI
scaffolding init function, etc).  The static code can then define a
generic `QueueCallback` function that looks up the callback interface
info using the interface ID and then makes the call.

Allow UniFFI functions to run on the main thread rather than always
being dispatched to a worker thread.  This allows us to test invoking
callback interfaces from the main thread thread. I don't think we will
use this much currently, since we don't want to block the main thread
for any significant amount of time. However, this will pair well with
the next step in the project which is async -- allowing async Rust
functions to call async JS functions. In that scenario, dispatching to
the worker thread is unnecessary.

Callback interface objects present a potential memory leak, since you
can easily create a cycle between a JS Callback object and a UniFFIed
Rust object, and the GC has no way of detecting it.  To try to detect
these there's some shutdown code that checks that there are no callbacks
registered during shutdown and prevents any future callbacks from being
registered.

Added a `config.toml` file and code to parse it.  This is needed to
specify which functions should run on the main thread.

Updated the git commits for the several UniFFI examples/fixtures.

Differential Revision: https://phabricator.services.mozilla.com/D156116
This commit is contained in:
Ben Dean-Kawamura 2023-01-03 20:57:53 +00:00
Родитель 192b74fdff
Коммит 79c4dcd5b0
61 изменённых файлов: 3684 добавлений и 1742 удалений

Просмотреть файл

@ -102,7 +102,7 @@ replace-with = "vendored-sources"
[source."https://github.com/mozilla/uniffi-rs.git"]
git = "https://github.com/mozilla/uniffi-rs.git"
rev = "bb2039f077a29dba0879372a67e764e6ace8e33f"
rev = "846612a1d4fb5d11e246bf0682da4a499409424c"
replace-with = "vendored-sources"
[source."https://github.com/rust-minidump/minidump-writer.git"]

33
Cargo.lock сгенерированный
Просмотреть файл

@ -2230,6 +2230,7 @@ dependencies = [
"uniffi-example-rondpoint",
"uniffi-example-sprites",
"uniffi-example-todolist",
"uniffi-fixture-callbacks",
"uniffi-fixture-external-types",
"url",
"viaduct",
@ -5769,8 +5770,8 @@ dependencies = [
[[package]]
name = "uniffi-example-arithmetic"
version = "0.18.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=bb2039f077a29dba0879372a67e764e6ace8e33f#bb2039f077a29dba0879372a67e764e6ace8e33f"
version = "0.21.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=846612a1d4fb5d11e246bf0682da4a499409424c#846612a1d4fb5d11e246bf0682da4a499409424c"
dependencies = [
"thiserror",
"uniffi",
@ -5793,8 +5794,8 @@ dependencies = [
[[package]]
name = "uniffi-example-geometry"
version = "0.18.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=bb2039f077a29dba0879372a67e764e6ace8e33f#bb2039f077a29dba0879372a67e764e6ace8e33f"
version = "0.21.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=846612a1d4fb5d11e246bf0682da4a499409424c#846612a1d4fb5d11e246bf0682da4a499409424c"
dependencies = [
"uniffi",
"uniffi_build",
@ -5803,8 +5804,8 @@ dependencies = [
[[package]]
name = "uniffi-example-rondpoint"
version = "0.18.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=bb2039f077a29dba0879372a67e764e6ace8e33f#bb2039f077a29dba0879372a67e764e6ace8e33f"
version = "0.21.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=846612a1d4fb5d11e246bf0682da4a499409424c#846612a1d4fb5d11e246bf0682da4a499409424c"
dependencies = [
"uniffi",
"uniffi_build",
@ -5813,8 +5814,8 @@ dependencies = [
[[package]]
name = "uniffi-example-sprites"
version = "0.18.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=bb2039f077a29dba0879372a67e764e6ace8e33f#bb2039f077a29dba0879372a67e764e6ace8e33f"
version = "0.21.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=846612a1d4fb5d11e246bf0682da4a499409424c#846612a1d4fb5d11e246bf0682da4a499409424c"
dependencies = [
"uniffi",
"uniffi_build",
@ -5823,10 +5824,20 @@ dependencies = [
[[package]]
name = "uniffi-example-todolist"
version = "0.18.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=bb2039f077a29dba0879372a67e764e6ace8e33f#bb2039f077a29dba0879372a67e764e6ace8e33f"
version = "0.21.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=846612a1d4fb5d11e246bf0682da4a499409424c#846612a1d4fb5d11e246bf0682da4a499409424c"
dependencies = [
"once_cell",
"thiserror",
"uniffi",
"uniffi_build",
"uniffi_macros",
]
[[package]]
name = "uniffi-fixture-callbacks"
version = "0.21.0"
dependencies = [
"lazy_static",
"thiserror",
"uniffi",
"uniffi_build",

Просмотреть файл

@ -12,14 +12,35 @@
//
// See https://mozilla.github.io/uniffi-rs/ for details.
// Define some ID types to identify various parts of the UDL interfaces. Using
// these IDs, allow this .webidl file to remain static, but support new
// interfaces. Using IDs is that the C++ and JS code need to agree on their
// meaning, which is handled by
// toolkit/components/uniffi-bindgen-gecko-js/src/ci_list.rs.
// Identifies a scaffolding function.
typedef unsigned long long UniFFIFunctionId;
// Identifies a pointer type
typedef unsigned long long UniFFIPointerId;
// Identifies a callback interface
typedef unsigned long UniFFICallbackInterfaceId;
// Identifies a method of a callback interface
typedef unsigned long UniFFICallbackMethodId;
// Handle for a callback interface instance
typedef unsigned long long UniFFICallbackObjectHandle;
// 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)
// - double is used for all numeric types and types which the JS code coerces
// to an int including Boolean and CallbackInterface.
// - ArrayBuffer is used for RustBuffer
// - UniFFIPointer is used for Arc pointers
typedef (double or ArrayBuffer or UniFFIPointer) UniFFIScaffoldingType;
@ -40,20 +61,47 @@ dictionary UniFFIScaffoldingCallResult {
ByteString internalErrorMessage;
};
// JS handler for calling a CallbackInterface method.
// The arguments and return value are always packed into an ArrayBuffer
callback UniFFICallbackHandler = undefined (UniFFICallbackObjectHandle objectId, UniFFICallbackMethodId methodId, ArrayBuffer aArgs);
// Functions to facilitate UniFFI scaffolding calls
//
// These should only be called by the generated code from UniFFI.
[ChromeOnly, Exposed=Window]
namespace UniFFIScaffolding {
// Call a scaffolding function on the worker thread.
//
// id is a unique identifier for the function, known to both the C++ and JS code
[Throws]
Promise<UniFFIScaffoldingCallResult> callAsync(unsigned long long id, UniFFIScaffoldingType... args);
Promise<UniFFIScaffoldingCallResult> callAsync(UniFFIFunctionId id, UniFFIScaffoldingType... args);
// Call a scaffolding function on the main thread
//
// id is a unique identifier for the function, known to both the C++ and JS code
[Throws]
UniFFIScaffoldingCallResult callSync(unsigned long long id, UniFFIScaffoldingType... args);
UniFFIScaffoldingCallResult callSync(UniFFIFunctionId id, UniFFIScaffoldingType... args);
// Read a UniFFIPointer from an ArrayBuffer
//
// id is a unique identifier for the pointer type, known to both the C++ and JS code
[Throws]
UniFFIPointer readPointer(unsigned long long id, ArrayBuffer buff, long position);
UniFFIPointer readPointer(UniFFIPointerId id, ArrayBuffer buff, long position);
// Write a UniFFIPointer to an ArrayBuffer
//
// id is a unique identifier for the pointer type, known to both the C++ and JS code
[Throws]
undefined writePointer(unsigned long long id, UniFFIPointer ptr, ArrayBuffer buff, long position);
undefined writePointer(UniFFIPointerId id, UniFFIPointer ptr, ArrayBuffer buff, long position);
// Register the global calblack handler
//
// This will be used to invoke all calls for a CallbackInterface.
// interfaceId is a unique identifier for the callback interface, known to both the C++ and JS code
[Throws]
undefined registerCallbackHandler(UniFFICallbackInterfaceId interfaceId, UniFFICallbackHandler handler);
// Deregister the global calblack handler
//
// This is called at shutdown to clear out the reference to the JS function.
[Throws]
undefined deregisterCallbackHandler(UniFFICallbackInterfaceId interfaceId);
};

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"90295a750f9c69ee799ac767d56eaee2c3218df7964f11c885b6910a31d07a25","build.rs":"05089b35ac197b5ff83c75872a70df023834141831d0c2051faa35b4c9df55ba","src/arithmetic.udl":"8554c6907ece627645f6b896f71430e5412bf19b0ac6becf63eb9a69868d0f7a","src/lib.rs":"92ebd9fc4d3403ab1960d2d8520c1217971147ea3aebff89228a61fcbb8b2af3","tests/bindings/test_arithmetic.kts":"e0e9347755db4e18f70b1b74c2d5a4aa328373015090ed959b46d65c2a205d92","tests/bindings/test_arithmetic.py":"3e41d69e21e96a6830197c760f3b7bddd754edc0c5515b7bd33b79cccb10f941","tests/bindings/test_arithmetic.rb":"ea0fdce0a4c7b557b427db77521da05240cd6e87d60a128ac2307fab3bbbc76d","tests/bindings/test_arithmetic.swift":"455b87d95fc690af9c35f9e43676e9c855dedddd2fc1c9e1cbaa6a02835c2d4c","tests/test_generated_bindings.rs":"09b0e79c7e769bcf5f3a8b768247a05892d408d48e0295f6737de3c8dab28479","uniffi.toml":"ad149df611a6e3a853a029d90a88a694660f6a4ebe18dcb5f9f503819761dacd"},"package":null}
{"files":{"Cargo.toml":"a4dd6685118bebe4eef690470cf112e51cc862162cf7d4c21c133d452ed7c488","build.rs":"05089b35ac197b5ff83c75872a70df023834141831d0c2051faa35b4c9df55ba","src/arithmetic.udl":"8554c6907ece627645f6b896f71430e5412bf19b0ac6becf63eb9a69868d0f7a","src/lib.rs":"92ebd9fc4d3403ab1960d2d8520c1217971147ea3aebff89228a61fcbb8b2af3","tests/bindings/test_arithmetic.kts":"e0e9347755db4e18f70b1b74c2d5a4aa328373015090ed959b46d65c2a205d92","tests/bindings/test_arithmetic.py":"3e41d69e21e96a6830197c760f3b7bddd754edc0c5515b7bd33b79cccb10f941","tests/bindings/test_arithmetic.rb":"ea0fdce0a4c7b557b427db77521da05240cd6e87d60a128ac2307fab3bbbc76d","tests/bindings/test_arithmetic.swift":"455b87d95fc690af9c35f9e43676e9c855dedddd2fc1c9e1cbaa6a02835c2d4c","tests/test_generated_bindings.rs":"09b0e79c7e769bcf5f3a8b768247a05892d408d48e0295f6737de3c8dab28479","uniffi.toml":"ad149df611a6e3a853a029d90a88a694660f6a4ebe18dcb5f9f503819761dacd"},"package":null}

Просмотреть файл

@ -1,7 +1,7 @@
[package]
name = "uniffi-example-arithmetic"
edition = "2021"
version = "0.18.0"
version = "0.21.0"
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
license = "MPL-2.0"
publish = false

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"15bbf6e8c0d438e7f776dfdcf8da5fefb41e4b5bacafe97d1fcb10389d07ed9b","build.rs":"94ca4e70e538a2159cb77157c227d487973756373c4b27ea5cea05a6698cb60b","src/geometry.udl":"7da7a6ec080c7117ec3c25206e23f9ed436e60b1a26fba34f991547680443550","src/lib.rs":"be9c624f691a8d1ebe3be6dbbcde44033759b8321a3a298453018dd69b9c14c7","tests/bindings/test_geometry.kts":"e537185e3c699df1c0468525700e8a38f9a504b2a663c38442146b951e38e9a7","tests/bindings/test_geometry.py":"3ea483b8a4fbe13aefa6641177ae149f75f734bc32bf0da533b97c1abf3dc317","tests/bindings/test_geometry.rb":"17c2fe8a7b477419a6646983dd88f1b07a0304b58a568c03e9bfa640d5b2df5c","tests/bindings/test_geometry.swift":"a61fec6bfe16020809e20e4da372748c24366767138c5672a0bfff85c4b62d78","tests/test_generated_bindings.rs":"8ba67396105b96cc554f78078c7a8c6e8ce86ecc868d97a069a5f60fd87c1a36","uniffi.toml":"5b28f45d3c2581a52cf886a502f034778a002815b66994e5da2081a5c9f5284b"},"package":null}
{"files":{"Cargo.toml":"ae167d6d92c007dac4db511c1b9ea2e4c7a7d6edb8f2fa95463b877825a3395a","build.rs":"94ca4e70e538a2159cb77157c227d487973756373c4b27ea5cea05a6698cb60b","src/geometry.udl":"7da7a6ec080c7117ec3c25206e23f9ed436e60b1a26fba34f991547680443550","src/lib.rs":"be9c624f691a8d1ebe3be6dbbcde44033759b8321a3a298453018dd69b9c14c7","tests/bindings/test_geometry.kts":"e537185e3c699df1c0468525700e8a38f9a504b2a663c38442146b951e38e9a7","tests/bindings/test_geometry.py":"3ea483b8a4fbe13aefa6641177ae149f75f734bc32bf0da533b97c1abf3dc317","tests/bindings/test_geometry.rb":"17c2fe8a7b477419a6646983dd88f1b07a0304b58a568c03e9bfa640d5b2df5c","tests/bindings/test_geometry.swift":"a61fec6bfe16020809e20e4da372748c24366767138c5672a0bfff85c4b62d78","tests/test_generated_bindings.rs":"8ba67396105b96cc554f78078c7a8c6e8ce86ecc868d97a069a5f60fd87c1a36","uniffi.toml":"5b28f45d3c2581a52cf886a502f034778a002815b66994e5da2081a5c9f5284b"},"package":null}

Просмотреть файл

@ -1,7 +1,7 @@
[package]
name = "uniffi-example-geometry"
edition = "2021"
version = "0.18.0"
version = "0.21.0"
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
license = "MPL-2.0"
publish = false

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"e26e9e2826e89bf73aed693d2cea2aa1e2ce3d32cb0f03136cc29352f851295c","build.rs":"c48df8045c6cf73a8f3b8e93af7878f4ce1e7baa11f0688d661405f339df4ba4","src/lib.rs":"70b9ab1fb944d3af1ce53ce097caf52d1ebbf0e18be1e70bf57e5cec96e76502","src/rondpoint.udl":"ca4d8720758608b06ffd5f81bfc73881fbd0693a7a5b21bfe61a4557ea052048","tests/bindings/test_rondpoint.kts":"87b3d507f4260aae4e4711263c13b7158b9a814cb97bf5219d1451f348cd7372","tests/bindings/test_rondpoint.py":"d618274170af767f8a5614a2565ea698b26ea3e1a222d5c110e7b2d00763e73b","tests/bindings/test_rondpoint.rb":"9cc49df311823d6caedbe7b05ff8c4da6329063c2ce16810192aaaa7edcdf5f5","tests/bindings/test_rondpoint.swift":"471cf430be35dcdc19b3166adbc08561e0bd939931edc37da974e0fd16a49331","tests/test_generated_bindings.rs":"5843b2c9d6b86b35ab932349d278d9f281493880a1395e0b7566e297fad36c7d"},"package":null}
{"files":{"Cargo.toml":"3cb89faf843332975007e3b6f9ad53cbcbdcaebc91c6abda2106b2b75ea01c70","build.rs":"c48df8045c6cf73a8f3b8e93af7878f4ce1e7baa11f0688d661405f339df4ba4","src/lib.rs":"b5eb9861fc436ab9fe9b0c00f95e374d812bbc0ea10b98cf746d38c96e44343a","src/rondpoint.udl":"ca4d8720758608b06ffd5f81bfc73881fbd0693a7a5b21bfe61a4557ea052048","tests/bindings/test_rondpoint.kts":"87b3d507f4260aae4e4711263c13b7158b9a814cb97bf5219d1451f348cd7372","tests/bindings/test_rondpoint.py":"d618274170af767f8a5614a2565ea698b26ea3e1a222d5c110e7b2d00763e73b","tests/bindings/test_rondpoint.rb":"9cc49df311823d6caedbe7b05ff8c4da6329063c2ce16810192aaaa7edcdf5f5","tests/bindings/test_rondpoint.swift":"471cf430be35dcdc19b3166adbc08561e0bd939931edc37da974e0fd16a49331","tests/test_generated_bindings.rs":"5843b2c9d6b86b35ab932349d278d9f281493880a1395e0b7566e297fad36c7d"},"package":null}

Просмотреть файл

@ -1,7 +1,7 @@
[package]
name = "uniffi-example-rondpoint"
edition = "2021"
version = "0.18.0"
version = "0.21.0"
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
license = "MPL-2.0"
publish = false

Просмотреть файл

@ -179,7 +179,7 @@ impl Stringifier {
value.to_string()
}
fn well_known_string(&self, value: String) -> String {
format!("uniffi 💚 {}!", value)
format!("uniffi 💚 {value}!")
}
}

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"b288fc6b1e909cffdb5171a247f268884a2483d9f97f1a24a679681fb418bd8d","build.rs":"d36e4ff477007611d216e60998d6d8a51b33895bb95159e3d7732e2b8cbc1783","src/lib.rs":"79ae1ea584942b25c108a26df79a781a63d66f8fb37c4dacfc04d180752effcb","src/sprites.udl":"bfd35f04ba0549301189dfb8fc45b0f39bad00956c324f33be0e845fb7ff78aa","tests/bindings/test_sprites.kts":"06ed115325f37ce59ed6f33e2d651cd2aa352fddcc644580f62a6da6ca075844","tests/bindings/test_sprites.py":"2e6ce838cfb387586257703c3500062438e840dd7ae57d185cdc244dc0745b8f","tests/bindings/test_sprites.rb":"6289a1833c7c8f4583ee4f0488d680de2ee46cfb203095a9b66d7234e2f07d53","tests/bindings/test_sprites.swift":"b2c0a6f4d5edfd7de7c2ba77b838865ffda153a6f364f273456175192d3e6e00","tests/test_generated_bindings.rs":"920c532011c8a6c20bdb1f39c50ef7a2803729a62a1bd425d81e40300958778a"},"package":null}
{"files":{"Cargo.toml":"78217b44063b2583832205fcbc5be8f1e92d4a77b58a97718edbdc9b2c60e604","build.rs":"d36e4ff477007611d216e60998d6d8a51b33895bb95159e3d7732e2b8cbc1783","src/lib.rs":"857ae59f3194cb7fe117a308854bc793b2b56441e297bd0e327795fd435494da","src/sprites.udl":"bfd35f04ba0549301189dfb8fc45b0f39bad00956c324f33be0e845fb7ff78aa","tests/bindings/test_sprites.kts":"06ed115325f37ce59ed6f33e2d651cd2aa352fddcc644580f62a6da6ca075844","tests/bindings/test_sprites.py":"2e6ce838cfb387586257703c3500062438e840dd7ae57d185cdc244dc0745b8f","tests/bindings/test_sprites.rb":"6289a1833c7c8f4583ee4f0488d680de2ee46cfb203095a9b66d7234e2f07d53","tests/bindings/test_sprites.swift":"b2c0a6f4d5edfd7de7c2ba77b838865ffda153a6f364f273456175192d3e6e00","tests/test_generated_bindings.rs":"920c532011c8a6c20bdb1f39c50ef7a2803729a62a1bd425d81e40300958778a"},"package":null}

Просмотреть файл

@ -1,7 +1,7 @@
[package]
name = "uniffi-example-sprites"
edition = "2021"
version = "0.18.0"
version = "0.21.0"
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
license = "MPL-2.0"
publish = false

Просмотреть файл

@ -58,7 +58,7 @@ impl Sprite {
fn move_by(&self, direction: Vector) {
let mut current_position = self.current_position.write().unwrap();
*current_position = translate(&*current_position, direction)
*current_position = translate(&current_position, direction)
}
}

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"4f4fc40bccf4ca5b105ea2abdbcdc6758ba7271d7d4ceb1e8ed45e3de227c2a6","build.rs":"ca26833c671cfe14a8275c276c197ab228cb1639b34cae31bb3805221ecc1245","src/lib.rs":"6a38904924681aed26b74876ad0480fedf8e8b2640cd2b04531a55aba8fc5592","src/todolist.udl":"1f8a24049c2340b9184e95facfc191ecdcb91541729ae7f20b4625d67685f13c","tests/bindings/test_todolist.kts":"f3d29b48e0193563fc4f131d91ea697f758174dcdb80ea554f233949e575bf55","tests/bindings/test_todolist.py":"f7430af9347df0daa954d38bc2203ce400affbb9a53fced4bb67a6796afa0664","tests/bindings/test_todolist.rb":"6524b5271a9cc0e2d78ca9f86ccb6973889926688a0843b4505a4f62d48f6dcb","tests/bindings/test_todolist.swift":"d1911b85fe0c8c0b42e5421b5af5d7359c9a65bba477d23560eb4b0f52e80662","tests/test_generated_bindings.rs":"25108de454213659c3eacd643a24c49099757a6b6da501fdb50874f574bd30c5"},"package":null}
{"files":{"Cargo.toml":"1bd2d172cd1b8d546c9b15bae57d9cfa5ff4f8e2bbba50299cafa5a693577d15","build.rs":"ca26833c671cfe14a8275c276c197ab228cb1639b34cae31bb3805221ecc1245","src/lib.rs":"338494783dbbcd8abbc7a1b5206f52296064091faa0a04e2d622a0d370ad12fe","src/todolist.udl":"1f8a24049c2340b9184e95facfc191ecdcb91541729ae7f20b4625d67685f13c","tests/bindings/test_todolist.kts":"f3d29b48e0193563fc4f131d91ea697f758174dcdb80ea554f233949e575bf55","tests/bindings/test_todolist.py":"f7430af9347df0daa954d38bc2203ce400affbb9a53fced4bb67a6796afa0664","tests/bindings/test_todolist.rb":"6524b5271a9cc0e2d78ca9f86ccb6973889926688a0843b4505a4f62d48f6dcb","tests/bindings/test_todolist.swift":"d1911b85fe0c8c0b42e5421b5af5d7359c9a65bba477d23560eb4b0f52e80662","tests/test_generated_bindings.rs":"25108de454213659c3eacd643a24c49099757a6b6da501fdb50874f574bd30c5"},"package":null}

Просмотреть файл

@ -1,7 +1,7 @@
[package]
name = "uniffi-example-todolist"
edition = "2021"
version = "0.18.0"
version = "0.21.0"
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
license = "MPL-2.0"
publish = false
@ -13,8 +13,8 @@ name = "uniffi_todolist"
[dependencies]
uniffi_macros = {path = "../../uniffi_macros"}
uniffi = {path = "../../uniffi", features=["builtin-bindgen"]}
once_cell = "1.12"
thiserror = "1.0"
lazy_static = "1.4"
[build-dependencies]
uniffi_build = {path = "../../uniffi_build", features=["builtin-bindgen"]}

Просмотреть файл

@ -4,18 +4,18 @@
use std::sync::{Arc, RwLock};
use once_cell::sync::Lazy;
#[derive(Debug, Clone)]
pub struct TodoEntry {
text: String,
}
lazy_static::lazy_static! {
// There is a single "default" TodoList that can be shared
// by all consumers of this component. Depending on requirements,
// a real app might like to use a `Weak<>` rather than an `Arc<>`
// here to reduce the risk of circular references.
static ref DEFAULT_LIST: RwLock<Option<Arc<TodoList>>> = RwLock::new(None);
}
// There is a single "default" TodoList that can be shared
// by all consumers of this component. Depending on requirements,
// a real app might like to use a `Weak<>` rather than an `Arc<>`
// here to reduce the risk of circular references.
static DEFAULT_LIST: Lazy<RwLock<Option<Arc<TodoList>>>> = Lazy::new(|| RwLock::new(None));
#[derive(Debug, thiserror::Error)]
pub enum TodoError {

Просмотреть файл

@ -5,7 +5,10 @@
"use strict";
var EXPORTED_SYMBOLS = [];
// Objects intended to be used in the unit tests
var UnitTestObjs = {};
var EXPORTED_SYMBOLS = ["UnitTestObjs"];
// Write/Read data to/from an ArrayBuffer
class ArrayBufferDataStream {
@ -103,7 +106,6 @@ class ArrayBufferDataStream {
this.pos += 8;
}
readFloat32() {
let rv = this.dataView.getFloat32(this.pos);
this.pos += 4;
@ -220,6 +222,10 @@ class UniFFIError {
constructor(message) {
this.message = message;
}
toString() {
return `UniFFIError: ${this.message}`
}
}
class UniFFIInternalError extends UniFFIError {}
@ -323,200 +329,226 @@ class TabsBridgedEngine {
}
this[uniffiObjectPtr] = opts[constructUniffiObject];
}
lastSync() {
const liftResult = (result) => FfiConverterI64.lift(result);
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
7, // tabs:tabs_edc9_TabsBridgedEngine_last_sync
FfiConverterTypeTabsBridgedEngine.lower(this),
)
const liftResult = (result) => FfiConverterI64.lift(result);
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
7, // tabs:tabs_edc9_TabsBridgedEngine_last_sync
FfiConverterTypeTabsBridgedEngine.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
setLastSync(lastSync) {
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
FfiConverterI64.checkType("lastSync", lastSync);
return UniFFIScaffolding.callAsync(
8, // tabs:tabs_edc9_TabsBridgedEngine_set_last_sync
FfiConverterTypeTabsBridgedEngine.lower(this),
FfiConverterI64.lower(lastSync),
)
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
FfiConverterI64.checkType("lastSync", lastSync);
return UniFFIScaffolding.callAsync(
8, // tabs:tabs_edc9_TabsBridgedEngine_set_last_sync
FfiConverterTypeTabsBridgedEngine.lower(this),
FfiConverterI64.lower(lastSync),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
syncId() {
const liftResult = (result) => FfiConverterOptionalstring.lift(result);
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
9, // tabs:tabs_edc9_TabsBridgedEngine_sync_id
FfiConverterTypeTabsBridgedEngine.lower(this),
)
const liftResult = (result) => FfiConverterOptionalstring.lift(result);
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
9, // tabs:tabs_edc9_TabsBridgedEngine_sync_id
FfiConverterTypeTabsBridgedEngine.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
resetSyncId() {
const liftResult = (result) => FfiConverterString.lift(result);
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
10, // tabs:tabs_edc9_TabsBridgedEngine_reset_sync_id
FfiConverterTypeTabsBridgedEngine.lower(this),
)
const liftResult = (result) => FfiConverterString.lift(result);
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
10, // tabs:tabs_edc9_TabsBridgedEngine_reset_sync_id
FfiConverterTypeTabsBridgedEngine.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
ensureCurrentSyncId(newSyncId) {
const liftResult = (result) => FfiConverterString.lift(result);
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
FfiConverterString.checkType("newSyncId", newSyncId);
return UniFFIScaffolding.callAsync(
11, // tabs:tabs_edc9_TabsBridgedEngine_ensure_current_sync_id
FfiConverterTypeTabsBridgedEngine.lower(this),
FfiConverterString.lower(newSyncId),
)
const liftResult = (result) => FfiConverterString.lift(result);
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
FfiConverterString.checkType("newSyncId", newSyncId);
return UniFFIScaffolding.callAsync(
11, // tabs:tabs_edc9_TabsBridgedEngine_ensure_current_sync_id
FfiConverterTypeTabsBridgedEngine.lower(this),
FfiConverterString.lower(newSyncId),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
prepareForSync(clientData) {
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
FfiConverterString.checkType("clientData", clientData);
return UniFFIScaffolding.callAsync(
12, // tabs:tabs_edc9_TabsBridgedEngine_prepare_for_sync
FfiConverterTypeTabsBridgedEngine.lower(this),
FfiConverterString.lower(clientData),
)
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
FfiConverterString.checkType("clientData", clientData);
return UniFFIScaffolding.callAsync(
12, // tabs:tabs_edc9_TabsBridgedEngine_prepare_for_sync
FfiConverterTypeTabsBridgedEngine.lower(this),
FfiConverterString.lower(clientData),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
syncStarted() {
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
13, // tabs:tabs_edc9_TabsBridgedEngine_sync_started
FfiConverterTypeTabsBridgedEngine.lower(this),
)
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
13, // tabs:tabs_edc9_TabsBridgedEngine_sync_started
FfiConverterTypeTabsBridgedEngine.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
storeIncoming(incomingEnvelopesAsJson) {
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
FfiConverterSequencestring.checkType("incomingEnvelopesAsJson", incomingEnvelopesAsJson);
return UniFFIScaffolding.callAsync(
14, // tabs:tabs_edc9_TabsBridgedEngine_store_incoming
FfiConverterTypeTabsBridgedEngine.lower(this),
FfiConverterSequencestring.lower(incomingEnvelopesAsJson),
)
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
FfiConverterSequencestring.checkType("incomingEnvelopesAsJson", incomingEnvelopesAsJson);
return UniFFIScaffolding.callAsync(
14, // tabs:tabs_edc9_TabsBridgedEngine_store_incoming
FfiConverterTypeTabsBridgedEngine.lower(this),
FfiConverterSequencestring.lower(incomingEnvelopesAsJson),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
apply() {
const liftResult = (result) => FfiConverterSequencestring.lift(result);
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
15, // tabs:tabs_edc9_TabsBridgedEngine_apply
FfiConverterTypeTabsBridgedEngine.lower(this),
)
const liftResult = (result) => FfiConverterSequencestring.lift(result);
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
15, // tabs:tabs_edc9_TabsBridgedEngine_apply
FfiConverterTypeTabsBridgedEngine.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
setUploaded(newTimestamp,uploadedIds) {
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
FfiConverterI64.checkType("newTimestamp", newTimestamp);
FfiConverterSequenceTypeTabsGuid.checkType("uploadedIds", uploadedIds);
return UniFFIScaffolding.callAsync(
16, // tabs:tabs_edc9_TabsBridgedEngine_set_uploaded
FfiConverterTypeTabsBridgedEngine.lower(this),
FfiConverterI64.lower(newTimestamp),
FfiConverterSequenceTypeTabsGuid.lower(uploadedIds),
)
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
FfiConverterI64.checkType("newTimestamp", newTimestamp);
FfiConverterSequenceTypeTabsGuid.checkType("uploadedIds", uploadedIds);
return UniFFIScaffolding.callAsync(
16, // tabs:tabs_edc9_TabsBridgedEngine_set_uploaded
FfiConverterTypeTabsBridgedEngine.lower(this),
FfiConverterI64.lower(newTimestamp),
FfiConverterSequenceTypeTabsGuid.lower(uploadedIds),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
syncFinished() {
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
17, // tabs:tabs_edc9_TabsBridgedEngine_sync_finished
FfiConverterTypeTabsBridgedEngine.lower(this),
)
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
17, // tabs:tabs_edc9_TabsBridgedEngine_sync_finished
FfiConverterTypeTabsBridgedEngine.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
reset() {
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
18, // tabs:tabs_edc9_TabsBridgedEngine_reset
FfiConverterTypeTabsBridgedEngine.lower(this),
)
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
18, // tabs:tabs_edc9_TabsBridgedEngine_reset
FfiConverterTypeTabsBridgedEngine.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
wipe() {
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
19, // tabs:tabs_edc9_TabsBridgedEngine_wipe
FfiConverterTypeTabsBridgedEngine.lower(this),
)
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
19, // tabs:tabs_edc9_TabsBridgedEngine_wipe
FfiConverterTypeTabsBridgedEngine.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
}
@ -569,116 +601,128 @@ class TabsStore {
* to a newly constructed TabsStore
*/
static init(path) {
const liftResult = (result) => FfiConverterTypeTabsStore.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterString.checkType("path", path);
return UniFFIScaffolding.callAsync(
0, // tabs:tabs_edc9_TabsStore_new
FfiConverterString.lower(path),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
const liftResult = (result) => FfiConverterTypeTabsStore.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterString.checkType("path", path);
return UniFFIScaffolding.callAsync(
0, // tabs:tabs_edc9_TabsStore_new
FfiConverterString.lower(path),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
getAll() {
const liftResult = (result) => FfiConverterSequenceTypeClientRemoteTabs.lift(result);
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
1, // tabs:tabs_edc9_TabsStore_get_all
FfiConverterTypeTabsStore.lower(this),
)
const liftResult = (result) => FfiConverterSequenceTypeClientRemoteTabs.lift(result);
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
1, // tabs:tabs_edc9_TabsStore_get_all
FfiConverterTypeTabsStore.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
setLocalTabs(remoteTabs) {
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
FfiConverterSequenceTypeRemoteTabRecord.checkType("remoteTabs", remoteTabs);
return UniFFIScaffolding.callAsync(
2, // tabs:tabs_edc9_TabsStore_set_local_tabs
FfiConverterTypeTabsStore.lower(this),
FfiConverterSequenceTypeRemoteTabRecord.lower(remoteTabs),
)
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
FfiConverterSequenceTypeRemoteTabRecord.checkType("remoteTabs", remoteTabs);
return UniFFIScaffolding.callAsync(
2, // tabs:tabs_edc9_TabsStore_set_local_tabs
FfiConverterTypeTabsStore.lower(this),
FfiConverterSequenceTypeRemoteTabRecord.lower(remoteTabs),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
registerWithSyncManager() {
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
3, // tabs:tabs_edc9_TabsStore_register_with_sync_manager
FfiConverterTypeTabsStore.lower(this),
)
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
3, // tabs:tabs_edc9_TabsStore_register_with_sync_manager
FfiConverterTypeTabsStore.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
reset() {
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
4, // tabs:tabs_edc9_TabsStore_reset
FfiConverterTypeTabsStore.lower(this),
)
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
4, // tabs:tabs_edc9_TabsStore_reset
FfiConverterTypeTabsStore.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
sync(keyId,accessToken,syncKey,tokenserverUrl,localId) {
const liftResult = (result) => FfiConverterString.lift(result);
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
FfiConverterString.checkType("keyId", keyId);
FfiConverterString.checkType("accessToken", accessToken);
FfiConverterString.checkType("syncKey", syncKey);
FfiConverterString.checkType("tokenserverUrl", tokenserverUrl);
FfiConverterString.checkType("localId", localId);
return UniFFIScaffolding.callAsync(
5, // tabs:tabs_edc9_TabsStore_sync
FfiConverterTypeTabsStore.lower(this),
FfiConverterString.lower(keyId),
FfiConverterString.lower(accessToken),
FfiConverterString.lower(syncKey),
FfiConverterString.lower(tokenserverUrl),
FfiConverterString.lower(localId),
)
const liftResult = (result) => FfiConverterString.lift(result);
const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
const functionCall = () => {
FfiConverterString.checkType("keyId", keyId);
FfiConverterString.checkType("accessToken", accessToken);
FfiConverterString.checkType("syncKey", syncKey);
FfiConverterString.checkType("tokenserverUrl", tokenserverUrl);
FfiConverterString.checkType("localId", localId);
return UniFFIScaffolding.callAsync(
5, // tabs:tabs_edc9_TabsStore_sync
FfiConverterTypeTabsStore.lower(this),
FfiConverterString.lower(keyId),
FfiConverterString.lower(accessToken),
FfiConverterString.lower(syncKey),
FfiConverterString.lower(tokenserverUrl),
FfiConverterString.lower(localId),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
bridgedEngine() {
const liftResult = (result) => FfiConverterTypeTabsBridgedEngine.lift(result);
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
6, // tabs:tabs_edc9_TabsStore_bridged_engine
FfiConverterTypeTabsStore.lower(this),
)
const liftResult = (result) => FfiConverterTypeTabsBridgedEngine.lift(result);
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
6, // tabs:tabs_edc9_TabsStore_bridged_engine
FfiConverterTypeTabsStore.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
}
@ -918,10 +962,13 @@ class SyncError extends TabsApiError {
constructor(
reason,
...params
) {
super(...params);
this.reason = reason;
}
) {
super(...params);
this.reason = reason;
}
toString() {
return `SyncError: ${super.toString()}`
}
}
EXPORTED_SYMBOLS.push("SyncError");
class SqlError extends TabsApiError {
@ -929,10 +976,13 @@ class SqlError extends TabsApiError {
constructor(
reason,
...params
) {
super(...params);
this.reason = reason;
}
) {
super(...params);
this.reason = reason;
}
toString() {
return `SqlError: ${super.toString()}`
}
}
EXPORTED_SYMBOLS.push("SqlError");
class UnexpectedTabsError extends TabsApiError {
@ -940,10 +990,13 @@ class UnexpectedTabsError extends TabsApiError {
constructor(
reason,
...params
) {
super(...params);
this.reason = reason;
}
) {
super(...params);
this.reason = reason;
}
toString() {
return `UnexpectedTabsError: ${super.toString()}`
}
}
EXPORTED_SYMBOLS.push("UnexpectedTabsError");
@ -963,9 +1016,46 @@ class FfiConverterTypeTabsApiError extends FfiConverterArrayBuffer {
FfiConverterString.read(dataStream)
);
default:
return new Error("Unknown TabsApiError variant");
throw new Error("Unknown TabsApiError variant");
}
}
static computeSize(value) {
// Size of the Int indicating the variant
let totalSize = 4;
if (value instanceof SyncError) {
totalSize += FfiConverterString.computeSize(value.reason);
return totalSize;
}
if (value instanceof SqlError) {
totalSize += FfiConverterString.computeSize(value.reason);
return totalSize;
}
if (value instanceof UnexpectedTabsError) {
totalSize += FfiConverterString.computeSize(value.reason);
return totalSize;
}
throw new Error("Unknown TabsApiError variant");
}
static write(dataStream, value) {
if (value instanceof SyncError) {
dataStream.writeInt32(1);
FfiConverterString.write(dataStream, value.reason);
return;
}
if (value instanceof SqlError) {
dataStream.writeInt32(2);
FfiConverterString.write(dataStream, value.reason);
return;
}
if (value instanceof UnexpectedTabsError) {
dataStream.writeInt32(3);
FfiConverterString.write(dataStream, value.reason);
return;
}
throw new Error("Unknown TabsApiError variant");
}
static errorClass = TabsApiError;
}
// Export the FFIConverter object to make external types work.

Просмотреть файл

@ -0,0 +1,5 @@
[fixture_callbacks.receiver_thread]
default = "worker"
main = [
"log_even_numbers_main_thread",
]

Просмотреть файл

@ -5,7 +5,10 @@
"use strict";
var EXPORTED_SYMBOLS = [];
// Objects intended to be used in the unit tests
var UnitTestObjs = {};
var EXPORTED_SYMBOLS = ["UnitTestObjs"];
// Write/Read data to/from an ArrayBuffer
class ArrayBufferDataStream {
@ -103,7 +106,6 @@ class ArrayBufferDataStream {
this.pos += 8;
}
readFloat32() {
let rv = this.dataView.getFloat32(this.pos);
this.pos += 4;
@ -180,6 +182,10 @@ class UniFFIError {
constructor(message) {
this.message = message;
}
toString() {
return `UniFFIError: ${this.message}`
}
}
class UniFFIInternalError extends UniFFIError {}
@ -310,6 +316,9 @@ class IntegerOverflow extends ArithmeticError {
super(...params);
this.message = message;
}
toString() {
return `IntegerOverflow: ${super.toString()}`
}
}
EXPORTED_SYMBOLS.push("IntegerOverflow");
@ -319,9 +328,26 @@ class FfiConverterTypeArithmeticError extends FfiConverterArrayBuffer {
case 1:
return new IntegerOverflow(FfiConverterString.read(dataStream));
default:
return new Error("Unknown ArithmeticError variant");
throw new Error("Unknown ArithmeticError variant");
}
}
static computeSize(value) {
// Size of the Int indicating the variant
let totalSize = 4;
if (value instanceof IntegerOverflow) {
return totalSize;
}
throw new Error("Unknown ArithmeticError variant");
}
static write(dataStream, value) {
if (value instanceof IntegerOverflow) {
dataStream.writeInt32(1);
return;
}
throw new Error("Unknown ArithmeticError variant");
}
static errorClass = ArithmeticError;
}
// Export the FFIConverter object to make external types work.
@ -332,85 +358,85 @@ EXPORTED_SYMBOLS.push("FfiConverterTypeArithmeticError");
function add(a,b) {
const liftResult = (result) => FfiConverterU64.lift(result);
const liftError = (data) => FfiConverterTypeArithmeticError.lift(data);
const functionCall = () => {
FfiConverterU64.checkType("a", a);
FfiConverterU64.checkType("b", b);
return UniFFIScaffolding.callAsync(
22, // arithmetic:arithmetic_906c_add
FfiConverterU64.lower(a),
FfiConverterU64.lower(b),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
const liftResult = (result) => FfiConverterU64.lift(result);
const liftError = (data) => FfiConverterTypeArithmeticError.lift(data);
const functionCall = () => {
FfiConverterU64.checkType("a", a);
FfiConverterU64.checkType("b", b);
return UniFFIScaffolding.callAsync(
22, // arithmetic:arithmetic_906c_add
FfiConverterU64.lower(a),
FfiConverterU64.lower(b),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
EXPORTED_SYMBOLS.push("add");
function sub(a,b) {
const liftResult = (result) => FfiConverterU64.lift(result);
const liftError = (data) => FfiConverterTypeArithmeticError.lift(data);
const functionCall = () => {
FfiConverterU64.checkType("a", a);
FfiConverterU64.checkType("b", b);
return UniFFIScaffolding.callAsync(
23, // arithmetic:arithmetic_906c_sub
FfiConverterU64.lower(a),
FfiConverterU64.lower(b),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
const liftResult = (result) => FfiConverterU64.lift(result);
const liftError = (data) => FfiConverterTypeArithmeticError.lift(data);
const functionCall = () => {
FfiConverterU64.checkType("a", a);
FfiConverterU64.checkType("b", b);
return UniFFIScaffolding.callAsync(
23, // arithmetic:arithmetic_906c_sub
FfiConverterU64.lower(a),
FfiConverterU64.lower(b),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
EXPORTED_SYMBOLS.push("sub");
function div(dividend,divisor) {
const liftResult = (result) => FfiConverterU64.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterU64.checkType("dividend", dividend);
FfiConverterU64.checkType("divisor", divisor);
return UniFFIScaffolding.callAsync(
24, // arithmetic:arithmetic_906c_div
FfiConverterU64.lower(dividend),
FfiConverterU64.lower(divisor),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
const liftResult = (result) => FfiConverterU64.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterU64.checkType("dividend", dividend);
FfiConverterU64.checkType("divisor", divisor);
return UniFFIScaffolding.callAsync(
24, // arithmetic:arithmetic_906c_div
FfiConverterU64.lower(dividend),
FfiConverterU64.lower(divisor),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
EXPORTED_SYMBOLS.push("div");
function equal(a,b) {
const liftResult = (result) => FfiConverterBool.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterU64.checkType("a", a);
FfiConverterU64.checkType("b", b);
return UniFFIScaffolding.callAsync(
25, // arithmetic:arithmetic_906c_equal
FfiConverterU64.lower(a),
FfiConverterU64.lower(b),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
const liftResult = (result) => FfiConverterBool.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterU64.checkType("a", a);
FfiConverterU64.checkType("b", b);
return UniFFIScaffolding.callAsync(
25, // arithmetic:arithmetic_906c_equal
FfiConverterU64.lower(a),
FfiConverterU64.lower(b),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
EXPORTED_SYMBOLS.push("equal");

Просмотреть файл

@ -5,7 +5,10 @@
"use strict";
var EXPORTED_SYMBOLS = [];
// Objects intended to be used in the unit tests
var UnitTestObjs = {};
var EXPORTED_SYMBOLS = ["UnitTestObjs"];
// Write/Read data to/from an ArrayBuffer
class ArrayBufferDataStream {
@ -103,7 +106,6 @@ class ArrayBufferDataStream {
this.pos += 8;
}
readFloat32() {
let rv = this.dataView.getFloat32(this.pos);
this.pos += 4;
@ -180,6 +182,10 @@ class UniFFIError {
constructor(message) {
this.message = message;
}
toString() {
return `UniFFIError: ${this.message}`
}
}
class UniFFIInternalError extends UniFFIError {}
@ -417,20 +423,20 @@ EXPORTED_SYMBOLS.push("FfiConverterTypeUrl");
function getCustomTypesDemo(demo) {
const liftResult = (result) => FfiConverterTypeCustomTypesDemo.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterOptionalTypeCustomTypesDemo.checkType("demo", demo);
return UniFFIScaffolding.callAsync(
107, // custom_types:custom_types_8ecd_get_custom_types_demo
FfiConverterOptionalTypeCustomTypesDemo.lower(demo),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
const liftResult = (result) => FfiConverterTypeCustomTypesDemo.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterOptionalTypeCustomTypesDemo.checkType("demo", demo);
return UniFFIScaffolding.callAsync(
109, // custom_types:custom_types_8ecd_get_custom_types_demo
FfiConverterOptionalTypeCustomTypesDemo.lower(demo),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
EXPORTED_SYMBOLS.push("getCustomTypesDemo");

Просмотреть файл

@ -5,7 +5,10 @@
"use strict";
var EXPORTED_SYMBOLS = [];
// Objects intended to be used in the unit tests
var UnitTestObjs = {};
var EXPORTED_SYMBOLS = ["UnitTestObjs"];
// Write/Read data to/from an ArrayBuffer
class ArrayBufferDataStream {
@ -103,7 +106,6 @@ class ArrayBufferDataStream {
this.pos += 8;
}
readFloat32() {
let rv = this.dataView.getFloat32(this.pos);
this.pos += 4;
@ -180,6 +182,10 @@ class UniFFIError {
constructor(message) {
this.message = message;
}
toString() {
return `UniFFIError: ${this.message}`
}
}
class UniFFIInternalError extends UniFFIError {}
@ -324,20 +330,20 @@ EXPORTED_SYMBOLS.push("FfiConverterTypePoint");
function gradient(value) {
const liftResult = (result) => FfiConverterF64.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterOptionalTypeLine.checkType("value", value);
return UniFFIScaffolding.callAsync(
108, // external_types:external_types_54cc_gradient
FfiConverterOptionalTypeLine.lower(value),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
const liftResult = (result) => FfiConverterF64.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterOptionalTypeLine.checkType("value", value);
return UniFFIScaffolding.callAsync(
110, // external_types:external_types_54cc_gradient
FfiConverterOptionalTypeLine.lower(value),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
EXPORTED_SYMBOLS.push("gradient");

Просмотреть файл

@ -0,0 +1,598 @@
// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate.
// Trust me, you don't want to mess with it!
"use strict";
// Objects intended to be used in the unit tests
var UnitTestObjs = {};
var EXPORTED_SYMBOLS = ["UnitTestObjs"];
// 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;
}
}
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;
}
toString() {
return `UniFFIError: ${this.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");
/**
* Handler for a single UniFFI CallbackInterface
*
* This class stores objects that implement a callback interface in a handle
* map, allowing them to be referenced by the Rust code using an integer
* handle.
*
* While the callback object is stored in the map, it allows the Rust code to
* call methods on the object using the callback object handle, a method id,
* and an ArrayBuffer packed with the method arguments.
*
* When the Rust code drops its reference, it sends a call with the methodId=0,
* which causes callback object to be removed from the map.
*/
class UniFFICallbackHandler {
#name;
#interfaceId;
#handleCounter;
#handleMap;
#methodHandlers;
#allowNewCallbacks
/**
* Create a UniFFICallbackHandler
* @param {string} name - Human-friendly name for this callback interface
* @param {int} interfaceId - Interface ID for this CallbackInterface.
* @param {UniFFICallbackMethodHandler[]} methodHandlers -- UniFFICallbackHandler for each method, in the same order as the UDL file
*/
constructor(name, interfaceId, methodHandlers) {
this.#name = name;
this.#interfaceId = interfaceId;
this.#handleCounter = 0;
this.#handleMap = new Map();
this.#methodHandlers = methodHandlers;
this.#allowNewCallbacks = true;
UniFFIScaffolding.registerCallbackHandler(this.#interfaceId, this.invokeCallback.bind(this));
Services.obs.addObserver(this, "xpcom-shutdown");
}
/**
* Store a callback object in the handle map and return the handle
*
* @param {obj} callbackObj - Object that implements the callback interface
* @returns {int} - Handle for this callback object, this is what gets passed back to Rust.
*/
storeCallbackObj(callbackObj) {
if (!this.#allowNewCallbacks) {
throw new UniFFIError(`No new callbacks allowed for ${this.#name}`);
}
const handle = this.#handleCounter;
this.#handleCounter += 1;
this.#handleMap.set(handle, new UniFFICallbackHandleMapEntry(callbackObj, Components.stack.caller.formattedStack.trim()));
return handle;
}
/**
* Get a previously stored callback object
*
* @param {int} handle - Callback object handle, returned from `storeCallbackObj()`
* @returns {obj} - Callback object
*/
getCallbackObj(handle) {
return this.#handleMap.get(handle).callbackObj;
}
/**
* Set if new callbacks are allowed for this handler
*
* This is called with false during shutdown to ensure the callback maps don't
* prevent JS objects from being GCed.
*/
setAllowNewCallbacks(allow) {
this.#allowNewCallbacks = allow
}
/**
* Check that no callbacks are currently registered
*
* If there are callbacks registered a UniFFIError will be thrown. This is
* called during shutdown to generate an alert if there are leaked callback
* interfaces.
*/
assertNoRegisteredCallbacks() {
if (this.#handleMap.size > 0) {
const entry = this.#handleMap.values().next().value;
throw new UniFFIError(`UniFFI interface ${this.#name} has ${this.#handleMap.size} registered callbacks at xpcom-shutdown. This likely indicates a UniFFI callback leak.\nStack trace for the first leaked callback:\n${entry.stackTrace}.`);
}
}
/**
* Invoke a method on a stored callback object
* @param {int} handle - Object handle
* @param {int} methodId - Method identifier. This the 1-based index of
* the method from the UDL file. 0 is the special drop method, which
* removes the callback object from the handle map.
* @param {ArrayBuffer} argsArrayBuffer - Arguments to pass to the method, packed in an ArrayBuffer
*/
invokeCallback(handle, methodId, argsArrayBuffer) {
try {
this.#invokeCallbackInner(handle, methodId, argsArrayBuffer);
} catch (e) {
console.error(`internal error invoking callback: ${e}`)
}
}
#invokeCallbackInner(handle, methodId, argsArrayBuffer) {
const callbackObj = this.getCallbackObj(handle);
if (callbackObj === undefined) {
throw new UniFFIError(`${this.#name}: invalid callback handle id: ${handle}`);
}
// Special-cased drop method, remove the object from the handle map and
// return an empty array buffer
if (methodId == 0) {
this.#handleMap.delete(handle);
return;
}
// Get the method data, converting from 1-based indexing
const methodHandler = this.#methodHandlers[methodId - 1];
if (methodHandler === undefined) {
throw new UniFFIError(`${this.#name}: invalid method id: ${methodId}`)
}
methodHandler.call(callbackObj, argsArrayBuffer);
}
/**
* xpcom-shutdown observer method
*
* This handles:
* - Deregistering ourselves as the UniFFI callback handler
* - Checks for any leftover stored callbacks which indicate memory leaks
*/
observe(aSubject, aTopic, aData) {
if (aTopic == "xpcom-shutdown") {
try {
this.setAllowNewCallbacks(false);
this.assertNoRegisteredCallbacks();
UniFFIScaffolding.deregisterCallbackHandler(this.#interfaceId);
} catch (ex) {
console.error(`UniFFI Callback interface error during xpcom-shutdown: ${ex}`);
Cc["@mozilla.org/xpcom/debug;1"]
.getService(Ci.nsIDebug2)
.abort(ex.filename, ex.lineNumber);
}
}
}
}
/**
* Handles calling a single method for a callback interface
*/
class UniFFICallbackMethodHandler {
#name;
#argsConverters;
/**
* Create a UniFFICallbackMethodHandler
* @param {string} name -- Name of the method to call on the callback object
* @param {FfiConverter[]} argsConverters - FfiConverter for each argument type
*/
constructor(name, argsConverters) {
this.#name = name;
this.#argsConverters = argsConverters;
}
/**
* Invoke the method
*
* @param {obj} callbackObj -- Object implementing the callback interface for this method
* @param {ArrayBuffer} argsArrayBuffer -- Arguments for the method, packed in an ArrayBuffer
*/
call(callbackObj, argsArrayBuffer) {
const argsStream = new ArrayBufferDataStream(argsArrayBuffer);
const args = this.#argsConverters.map(converter => converter.read(argsStream));
callbackObj[this.#name](...args);
}
}
/**
* UniFFICallbackHandler.handleMap entry
*
* @property callbackObj - Callback object, this must implement the callback interface.
* @property {string} stackTrace - Stack trace from when the callback object was registered. This is used to proved extra context when debugging leaked callback objects.
*/
class UniFFICallbackHandleMapEntry {
constructor(callbackObj, stackTrace) {
this.callbackObj = callbackObj;
this.stackTrace = stackTrace
}
}
class FfiConverterI32 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()
}
}
// Export the FFIConverter object to make external types work.
EXPORTED_SYMBOLS.push("FfiConverterI32");
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
}
}
// Export the FFIConverter object to make external types work.
EXPORTED_SYMBOLS.push("FfiConverterString");
class FfiConverterCallbackInterfaceLogger extends FfiConverter {
static lower(callbackObj) {
return callbackHandlerLogger.storeCallbackObj(callbackObj)
}
static lift(handleId) {
return callbackHandlerLogger.getCallbackObj(handleId)
}
static read(dataStream) {
return this.lift(dataStream.readInt64())
}
static write(dataStream, callbackObj) {
dataStream.writeInt64(this.lower(callbackObj))
}
static computeSize(callbackObj) {
return 8;
}
}
// Export the FFIConverter object to make external types work.
EXPORTED_SYMBOLS.push("FfiConverterCallbackInterfaceLogger");
class FfiConverterSequencei32 extends FfiConverterArrayBuffer {
static read(dataStream) {
const len = dataStream.readInt32();
const arr = [];
for (let i = 0; i < len; i++) {
arr.push(FfiConverterI32.read(dataStream));
}
return arr;
}
static write(dataStream, value) {
dataStream.writeInt32(value.length);
value.forEach((innerValue) => {
FfiConverterI32.write(dataStream, innerValue);
})
}
static computeSize(value) {
// The size of the length
let size = 4;
for (const innerValue of value) {
size += FfiConverterI32.computeSize(innerValue);
}
return size;
}
}
// Export the FFIConverter object to make external types work.
EXPORTED_SYMBOLS.push("FfiConverterSequencei32");
// Define callback interface handlers, this must come after the type loop since they reference the FfiConverters defined above.
const callbackHandlerLogger = new UniFFICallbackHandler(
"fixture_callbacks:Logger",
0,
[
new UniFFICallbackMethodHandler(
"log",
[
FfiConverterString,
],
),
new UniFFICallbackMethodHandler(
"finished",
[
],
),
]
);
// Allow the shutdown-related functionality to be tested in the unit tests
UnitTestObjs.callbackHandlerLogger = callbackHandlerLogger;
function logEvenNumbers(logger,items) {
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
FfiConverterCallbackInterfaceLogger.checkType("logger", logger);
FfiConverterSequencei32.checkType("items", items);
return UniFFIScaffolding.callAsync(
107, // fixture_callbacks:fixture_callbacks_1107_log_even_numbers
FfiConverterCallbackInterfaceLogger.lower(logger),
FfiConverterSequencei32.lower(items),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
EXPORTED_SYMBOLS.push("logEvenNumbers");
function logEvenNumbersMainThread(logger,items) {
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
FfiConverterCallbackInterfaceLogger.checkType("logger", logger);
FfiConverterSequencei32.checkType("items", items);
return UniFFIScaffolding.callSync(
108, // fixture_callbacks:fixture_callbacks_1107_log_even_numbers_main_thread
FfiConverterCallbackInterfaceLogger.lower(logger),
FfiConverterSequencei32.lower(items),
)
}
return handleRustResult(functionCall(), liftResult, liftError);
}
EXPORTED_SYMBOLS.push("logEvenNumbersMainThread");

Просмотреть файл

@ -5,7 +5,10 @@
"use strict";
var EXPORTED_SYMBOLS = [];
// Objects intended to be used in the unit tests
var UnitTestObjs = {};
var EXPORTED_SYMBOLS = ["UnitTestObjs"];
// Write/Read data to/from an ArrayBuffer
class ArrayBufferDataStream {
@ -103,7 +106,6 @@ class ArrayBufferDataStream {
this.pos += 8;
}
readFloat32() {
let rv = this.dataView.getFloat32(this.pos);
this.pos += 4;
@ -180,6 +182,10 @@ class UniFFIError {
constructor(message) {
this.message = message;
}
toString() {
return `UniFFIError: ${this.message}`
}
}
class UniFFIInternalError extends UniFFIError {}
@ -406,41 +412,41 @@ EXPORTED_SYMBOLS.push("FfiConverterOptionalTypePoint");
function gradient(ln) {
const liftResult = (result) => FfiConverterF64.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterTypeLine.checkType("ln", ln);
return UniFFIScaffolding.callAsync(
20, // geometry:geometry_1cce_gradient
FfiConverterTypeLine.lower(ln),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
const liftResult = (result) => FfiConverterF64.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterTypeLine.checkType("ln", ln);
return UniFFIScaffolding.callAsync(
20, // geometry:geometry_1cce_gradient
FfiConverterTypeLine.lower(ln),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
EXPORTED_SYMBOLS.push("gradient");
function intersection(ln1,ln2) {
const liftResult = (result) => FfiConverterOptionalTypePoint.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterTypeLine.checkType("ln1", ln1);
FfiConverterTypeLine.checkType("ln2", ln2);
return UniFFIScaffolding.callAsync(
21, // geometry:geometry_1cce_intersection
FfiConverterTypeLine.lower(ln1),
FfiConverterTypeLine.lower(ln2),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
const liftResult = (result) => FfiConverterOptionalTypePoint.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterTypeLine.checkType("ln1", ln1);
FfiConverterTypeLine.checkType("ln2", ln2);
return UniFFIScaffolding.callAsync(
21, // geometry:geometry_1cce_intersection
FfiConverterTypeLine.lower(ln1),
FfiConverterTypeLine.lower(ln2),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
EXPORTED_SYMBOLS.push("intersection");

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -5,7 +5,10 @@
"use strict";
var EXPORTED_SYMBOLS = [];
// Objects intended to be used in the unit tests
var UnitTestObjs = {};
var EXPORTED_SYMBOLS = ["UnitTestObjs"];
// Write/Read data to/from an ArrayBuffer
class ArrayBufferDataStream {
@ -103,7 +106,6 @@ class ArrayBufferDataStream {
this.pos += 8;
}
readFloat32() {
let rv = this.dataView.getFloat32(this.pos);
this.pos += 4;
@ -200,6 +202,10 @@ class UniFFIError {
constructor(message) {
this.message = message;
}
toString() {
return `UniFFIError: ${this.message}`
}
}
class UniFFIInternalError extends UniFFIError {}
@ -304,20 +310,20 @@ class Sprite {
* to a newly constructed Sprite
*/
static init(initialPosition) {
const liftResult = (result) => FfiConverterTypeSprite.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterOptionalTypePoint.checkType("initialPosition", initialPosition);
return UniFFIScaffolding.callAsync(
86, // sprites:sprites_accb_Sprite_new
FfiConverterOptionalTypePoint.lower(initialPosition),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
const liftResult = (result) => FfiConverterTypeSprite.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterOptionalTypePoint.checkType("initialPosition", initialPosition);
return UniFFIScaffolding.callAsync(
86, // sprites:sprites_accb_Sprite_new
FfiConverterOptionalTypePoint.lower(initialPosition),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
/**
* An async constructor for Sprite.
*
@ -325,68 +331,74 @@ class Sprite {
* to a newly constructed Sprite
*/
static newRelativeTo(reference,direction) {
const liftResult = (result) => FfiConverterTypeSprite.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterTypePoint.checkType("reference", reference);
FfiConverterTypeVector.checkType("direction", direction);
return UniFFIScaffolding.callAsync(
87, // sprites:sprites_accb_Sprite_new_relative_to
FfiConverterTypePoint.lower(reference),
FfiConverterTypeVector.lower(direction),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
const liftResult = (result) => FfiConverterTypeSprite.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterTypePoint.checkType("reference", reference);
FfiConverterTypeVector.checkType("direction", direction);
return UniFFIScaffolding.callAsync(
87, // sprites:sprites_accb_Sprite_new_relative_to
FfiConverterTypePoint.lower(reference),
FfiConverterTypeVector.lower(direction),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
getPosition() {
const liftResult = (result) => FfiConverterTypePoint.lift(result);
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
88, // sprites:sprites_accb_Sprite_get_position
FfiConverterTypeSprite.lower(this),
)
const liftResult = (result) => FfiConverterTypePoint.lift(result);
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
88, // sprites:sprites_accb_Sprite_get_position
FfiConverterTypeSprite.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
moveTo(position) {
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
FfiConverterTypePoint.checkType("position", position);
return UniFFIScaffolding.callAsync(
89, // sprites:sprites_accb_Sprite_move_to
FfiConverterTypeSprite.lower(this),
FfiConverterTypePoint.lower(position),
)
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
FfiConverterTypePoint.checkType("position", position);
return UniFFIScaffolding.callAsync(
89, // sprites:sprites_accb_Sprite_move_to
FfiConverterTypeSprite.lower(this),
FfiConverterTypePoint.lower(position),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
moveBy(direction) {
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
FfiConverterTypeVector.checkType("direction", direction);
return UniFFIScaffolding.callAsync(
90, // sprites:sprites_accb_Sprite_move_by
FfiConverterTypeSprite.lower(this),
FfiConverterTypeVector.lower(direction),
)
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
FfiConverterTypeVector.checkType("direction", direction);
return UniFFIScaffolding.callAsync(
90, // sprites:sprites_accb_Sprite_move_by
FfiConverterTypeSprite.lower(this),
FfiConverterTypeVector.lower(direction),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
}
@ -561,22 +573,22 @@ EXPORTED_SYMBOLS.push("FfiConverterOptionalTypePoint");
function translate(position,direction) {
const liftResult = (result) => FfiConverterTypePoint.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterTypePoint.checkType("position", position);
FfiConverterTypeVector.checkType("direction", direction);
return UniFFIScaffolding.callAsync(
91, // sprites:sprites_accb_translate
FfiConverterTypePoint.lower(position),
FfiConverterTypeVector.lower(direction),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
const liftResult = (result) => FfiConverterTypePoint.lift(result);
const liftError = null;
const functionCall = () => {
FfiConverterTypePoint.checkType("position", position);
FfiConverterTypeVector.checkType("direction", direction);
return UniFFIScaffolding.callAsync(
91, // sprites:sprites_accb_translate
FfiConverterTypePoint.lower(position),
FfiConverterTypeVector.lower(direction),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
EXPORTED_SYMBOLS.push("translate");

Просмотреть файл

@ -5,7 +5,10 @@
"use strict";
var EXPORTED_SYMBOLS = [];
// Objects intended to be used in the unit tests
var UnitTestObjs = {};
var EXPORTED_SYMBOLS = ["UnitTestObjs"];
// Write/Read data to/from an ArrayBuffer
class ArrayBufferDataStream {
@ -103,7 +106,6 @@ class ArrayBufferDataStream {
this.pos += 8;
}
readFloat32() {
let rv = this.dataView.getFloat32(this.pos);
this.pos += 4;
@ -200,6 +202,10 @@ class UniFFIError {
constructor(message) {
this.message = message;
}
toString() {
return `UniFFIError: ${this.message}`
}
}
class UniFFIInternalError extends UniFFIError {}
@ -283,182 +289,204 @@ class TodoList {
* to a newly constructed TodoList
*/
static init() {
const liftResult = (result) => FfiConverterTypeTodoList.lift(result);
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
92, // todolist:todolist_aa33_TodoList_new
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
const liftResult = (result) => FfiConverterTypeTodoList.lift(result);
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
92, // todolist:todolist_aa33_TodoList_new
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
addItem(todo) {
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTodoError.lift(data);
const functionCall = () => {
FfiConverterString.checkType("todo", todo);
return UniFFIScaffolding.callAsync(
93, // todolist:todolist_aa33_TodoList_add_item
FfiConverterTypeTodoList.lower(this),
FfiConverterString.lower(todo),
)
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTodoError.lift(data);
const functionCall = () => {
FfiConverterString.checkType("todo", todo);
return UniFFIScaffolding.callAsync(
93, // todolist:todolist_aa33_TodoList_add_item
FfiConverterTypeTodoList.lower(this),
FfiConverterString.lower(todo),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
addEntry(entry) {
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTodoError.lift(data);
const functionCall = () => {
FfiConverterTypeTodoEntry.checkType("entry", entry);
return UniFFIScaffolding.callAsync(
94, // todolist:todolist_aa33_TodoList_add_entry
FfiConverterTypeTodoList.lower(this),
FfiConverterTypeTodoEntry.lower(entry),
)
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTodoError.lift(data);
const functionCall = () => {
FfiConverterTypeTodoEntry.checkType("entry", entry);
return UniFFIScaffolding.callAsync(
94, // todolist:todolist_aa33_TodoList_add_entry
FfiConverterTypeTodoList.lower(this),
FfiConverterTypeTodoEntry.lower(entry),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
getEntries() {
const liftResult = (result) => FfiConverterSequenceTypeTodoEntry.lift(result);
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
95, // todolist:todolist_aa33_TodoList_get_entries
FfiConverterTypeTodoList.lower(this),
)
const liftResult = (result) => FfiConverterSequenceTypeTodoEntry.lift(result);
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
95, // todolist:todolist_aa33_TodoList_get_entries
FfiConverterTypeTodoList.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
getItems() {
const liftResult = (result) => FfiConverterSequencestring.lift(result);
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
96, // todolist:todolist_aa33_TodoList_get_items
FfiConverterTypeTodoList.lower(this),
)
const liftResult = (result) => FfiConverterSequencestring.lift(result);
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
96, // todolist:todolist_aa33_TodoList_get_items
FfiConverterTypeTodoList.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
addEntries(entries) {
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
FfiConverterSequenceTypeTodoEntry.checkType("entries", entries);
return UniFFIScaffolding.callAsync(
97, // todolist:todolist_aa33_TodoList_add_entries
FfiConverterTypeTodoList.lower(this),
FfiConverterSequenceTypeTodoEntry.lower(entries),
)
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
FfiConverterSequenceTypeTodoEntry.checkType("entries", entries);
return UniFFIScaffolding.callAsync(
97, // todolist:todolist_aa33_TodoList_add_entries
FfiConverterTypeTodoList.lower(this),
FfiConverterSequenceTypeTodoEntry.lower(entries),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
addItems(items) {
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
FfiConverterSequencestring.checkType("items", items);
return UniFFIScaffolding.callAsync(
98, // todolist:todolist_aa33_TodoList_add_items
FfiConverterTypeTodoList.lower(this),
FfiConverterSequencestring.lower(items),
)
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
FfiConverterSequencestring.checkType("items", items);
return UniFFIScaffolding.callAsync(
98, // todolist:todolist_aa33_TodoList_add_items
FfiConverterTypeTodoList.lower(this),
FfiConverterSequencestring.lower(items),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
getLastEntry() {
const liftResult = (result) => FfiConverterTypeTodoEntry.lift(result);
const liftError = (data) => FfiConverterTypeTodoError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
99, // todolist:todolist_aa33_TodoList_get_last_entry
FfiConverterTypeTodoList.lower(this),
)
const liftResult = (result) => FfiConverterTypeTodoEntry.lift(result);
const liftError = (data) => FfiConverterTypeTodoError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
99, // todolist:todolist_aa33_TodoList_get_last_entry
FfiConverterTypeTodoList.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
getLast() {
const liftResult = (result) => FfiConverterString.lift(result);
const liftError = (data) => FfiConverterTypeTodoError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
100, // todolist:todolist_aa33_TodoList_get_last
FfiConverterTypeTodoList.lower(this),
)
const liftResult = (result) => FfiConverterString.lift(result);
const liftError = (data) => FfiConverterTypeTodoError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
100, // todolist:todolist_aa33_TodoList_get_last
FfiConverterTypeTodoList.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
getFirst() {
const liftResult = (result) => FfiConverterString.lift(result);
const liftError = (data) => FfiConverterTypeTodoError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
101, // todolist:todolist_aa33_TodoList_get_first
FfiConverterTypeTodoList.lower(this),
)
const liftResult = (result) => FfiConverterString.lift(result);
const liftError = (data) => FfiConverterTypeTodoError.lift(data);
const functionCall = () => {
return UniFFIScaffolding.callAsync(
101, // todolist:todolist_aa33_TodoList_get_first
FfiConverterTypeTodoList.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
clearItem(todo) {
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTodoError.lift(data);
const functionCall = () => {
FfiConverterString.checkType("todo", todo);
return UniFFIScaffolding.callAsync(
102, // todolist:todolist_aa33_TodoList_clear_item
FfiConverterTypeTodoList.lower(this),
FfiConverterString.lower(todo),
)
const liftResult = (result) => undefined;
const liftError = (data) => FfiConverterTypeTodoError.lift(data);
const functionCall = () => {
FfiConverterString.checkType("todo", todo);
return UniFFIScaffolding.callAsync(
102, // todolist:todolist_aa33_TodoList_clear_item
FfiConverterTypeTodoList.lower(this),
FfiConverterString.lower(todo),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
makeDefault() {
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
103, // todolist:todolist_aa33_TodoList_make_default
FfiConverterTypeTodoList.lower(this),
)
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
103, // todolist:todolist_aa33_TodoList_make_default
FfiConverterTypeTodoList.lower(this),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}}
}
@ -546,6 +574,9 @@ class TodoDoesNotExist extends TodoError {
super(...params);
this.message = message;
}
toString() {
return `TodoDoesNotExist: ${super.toString()}`
}
}
EXPORTED_SYMBOLS.push("TodoDoesNotExist");
class EmptyTodoList extends TodoError {
@ -554,6 +585,9 @@ class EmptyTodoList extends TodoError {
super(...params);
this.message = message;
}
toString() {
return `EmptyTodoList: ${super.toString()}`
}
}
EXPORTED_SYMBOLS.push("EmptyTodoList");
class DuplicateTodo extends TodoError {
@ -562,6 +596,9 @@ class DuplicateTodo extends TodoError {
super(...params);
this.message = message;
}
toString() {
return `DuplicateTodo: ${super.toString()}`
}
}
EXPORTED_SYMBOLS.push("DuplicateTodo");
class EmptyString extends TodoError {
@ -570,6 +607,9 @@ class EmptyString extends TodoError {
super(...params);
this.message = message;
}
toString() {
return `EmptyString: ${super.toString()}`
}
}
EXPORTED_SYMBOLS.push("EmptyString");
class DeligatedError extends TodoError {
@ -578,6 +618,9 @@ class DeligatedError extends TodoError {
super(...params);
this.message = message;
}
toString() {
return `DeligatedError: ${super.toString()}`
}
}
EXPORTED_SYMBOLS.push("DeligatedError");
@ -595,9 +638,54 @@ class FfiConverterTypeTodoError extends FfiConverterArrayBuffer {
case 5:
return new DeligatedError(FfiConverterString.read(dataStream));
default:
return new Error("Unknown TodoError variant");
throw new Error("Unknown TodoError variant");
}
}
static computeSize(value) {
// Size of the Int indicating the variant
let totalSize = 4;
if (value instanceof TodoDoesNotExist) {
return totalSize;
}
if (value instanceof EmptyTodoList) {
return totalSize;
}
if (value instanceof DuplicateTodo) {
return totalSize;
}
if (value instanceof EmptyString) {
return totalSize;
}
if (value instanceof DeligatedError) {
return totalSize;
}
throw new Error("Unknown TodoError variant");
}
static write(dataStream, value) {
if (value instanceof TodoDoesNotExist) {
dataStream.writeInt32(1);
return;
}
if (value instanceof EmptyTodoList) {
dataStream.writeInt32(2);
return;
}
if (value instanceof DuplicateTodo) {
dataStream.writeInt32(3);
return;
}
if (value instanceof EmptyString) {
dataStream.writeInt32(4);
return;
}
if (value instanceof DeligatedError) {
dataStream.writeInt32(5);
return;
}
throw new Error("Unknown TodoError variant");
}
static errorClass = TodoError;
}
// Export the FFIConverter object to make external types work.
@ -707,56 +795,56 @@ EXPORTED_SYMBOLS.push("FfiConverterSequenceTypeTodoEntry");
function getDefaultList() {
const liftResult = (result) => FfiConverterOptionalTypeTodoList.lift(result);
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
104, // todolist:todolist_aa33_get_default_list
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
const liftResult = (result) => FfiConverterOptionalTypeTodoList.lift(result);
const liftError = null;
const functionCall = () => {
return UniFFIScaffolding.callAsync(
104, // todolist:todolist_aa33_get_default_list
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
EXPORTED_SYMBOLS.push("getDefaultList");
function setDefaultList(list) {
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
FfiConverterTypeTodoList.checkType("list", list);
return UniFFIScaffolding.callAsync(
105, // todolist:todolist_aa33_set_default_list
FfiConverterTypeTodoList.lower(list),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
const liftResult = (result) => undefined;
const liftError = null;
const functionCall = () => {
FfiConverterTypeTodoList.checkType("list", list);
return UniFFIScaffolding.callAsync(
105, // todolist:todolist_aa33_set_default_list
FfiConverterTypeTodoList.lower(list),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
EXPORTED_SYMBOLS.push("setDefaultList");
function createEntryWith(todo) {
const liftResult = (result) => FfiConverterTypeTodoEntry.lift(result);
const liftError = (data) => FfiConverterTypeTodoError.lift(data);
const functionCall = () => {
FfiConverterString.checkType("todo", todo);
return UniFFIScaffolding.callAsync(
106, // todolist:todolist_aa33_create_entry_with
FfiConverterString.lower(todo),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
const liftResult = (result) => FfiConverterTypeTodoEntry.lift(result);
const liftError = (data) => FfiConverterTypeTodoError.lift(data);
const functionCall = () => {
FfiConverterString.checkType("todo", todo);
return UniFFIScaffolding.callAsync(
106, // todolist:todolist_aa33_create_entry_with
FfiConverterString.lower(todo),
)
}
try {
return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
} catch (error) {
return Promise.reject(error)
}
}
EXPORTED_SYMBOLS.push("createEntryWith");

Просмотреть файл

@ -10,6 +10,7 @@ components = [
"Arithmetic",
"CustomTypes",
"ExternalTypes",
"FixtureCallbacks",
"Geometry",
"Rondpoint",
"Sprites",

Просмотреть файл

@ -0,0 +1,47 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const { logEvenNumbers, logEvenNumbersMainThread } = ChromeUtils.import(
"resource://gre/modules/RustFixtureCallbacks.jsm"
);
class Logger {
constructor() {
this.messages = [];
this.finishedPromise = new Promise((resolve, reject) => {
this.finishedResolve = resolve;
this.finishedReject = reject;
});
}
log(message) {
this.messages.push(message);
}
finished() {
this.finishedResolve(true);
}
async waitForFinish() {
// Set a timeout to avoid hanging the tests if the Rust code fails to call finished().
do_timeout(2000, () =>
this.finishedReject("Timeout waiting for finished()")
);
return this.finishedPromise;
}
}
add_task(async function testLogEvenNumbers() {
async function runTest(logEvenNumbersFunc) {
const logger = new Logger();
logEvenNumbersFunc(logger, [1, 1, 2, 3, 5, 8, 13]);
await logger.waitForFinish();
Assert.deepEqual(logger.messages, [
"Saw even number: 2",
"Saw even number: 8",
]);
}
await runTest(logEvenNumbers);
await runTest(logEvenNumbersMainThread);
});

Просмотреть файл

@ -1,4 +1,5 @@
[test_arithmetic.js]
[test_callbacks.js]
[test_geometry.js]
[test_rondpoint.js]
[test_sprites.js]

Просмотреть файл

@ -20,6 +20,7 @@ FIXTURE_UDL_FILES = [
"third_party/rust/uniffi-example-rondpoint/src/rondpoint.udl",
"third_party/rust/uniffi-example-sprites/src/sprites.udl",
"third_party/rust/uniffi-example-todolist/src/todolist.udl",
"toolkit/components/uniffi-fixture-callbacks/src/callbacks.udl",
"toolkit/components/uniffi-example-custom-types/src/custom-types.udl",
"toolkit/components/uniffi-fixture-external-types/src/external-types.udl",
]

Просмотреть файл

@ -2,7 +2,7 @@
* 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
//! Manage the universe of ComponentInterfaces / Configs
//!
//! 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
@ -14,39 +14,43 @@
//! This module manages the list of ComponentInterface and the object ids.
use crate::render::cpp::ComponentInterfaceCppExt;
use crate::{Config, ConfigMap};
use anyhow::{bail, Context, Result};
use camino::Utf8PathBuf;
use std::collections::{BTreeSet, HashMap, HashSet};
use uniffi_bindgen::interface::{ComponentInterface, FFIFunction, Object};
use uniffi_bindgen::interface::{CallbackInterface, ComponentInterface, FFIFunction, Object};
pub struct ComponentInterfaceUniverse {
ci_list: Vec<ComponentInterface>,
fixture_ci_list: Vec<ComponentInterface>,
pub struct ComponentUniverse {
pub components: Vec<(ComponentInterface, Config)>,
pub fixture_components: Vec<(ComponentInterface, Config)>,
}
impl ComponentInterfaceUniverse {
pub fn new(udl_files: Vec<Utf8PathBuf>, fixture_udl_files: Vec<Utf8PathBuf>) -> Result<Self> {
let ci_list = udl_files
impl ComponentUniverse {
pub fn new(
udl_files: Vec<Utf8PathBuf>,
fixture_udl_files: Vec<Utf8PathBuf>,
config_map: ConfigMap,
) -> Result<Self> {
let components = udl_files
.into_iter()
.map(parse_udl_file)
.map(|udl_file| parse_udl_file(udl_file, &config_map))
.collect::<Result<Vec<_>>>()?;
let fixture_ci_list = fixture_udl_files
let fixture_components = fixture_udl_files
.into_iter()
.map(parse_udl_file)
.map(|udl_file| parse_udl_file(udl_file, &config_map))
.collect::<Result<Vec<_>>>()?;
Self::check_udl_namespaces_unique(&ci_list, &fixture_ci_list)?;
Ok(Self {
ci_list,
fixture_ci_list,
})
let universe = Self {
components,
fixture_components,
};
universe.check_udl_namespaces_unique()?;
universe.check_callback_interfaces()?;
Ok(universe)
}
fn check_udl_namespaces_unique(
ci_list: &Vec<ComponentInterface>,
fixture_ci_list: &Vec<ComponentInterface>,
) -> Result<()> {
fn check_udl_namespaces_unique(&self) -> Result<()> {
let mut set = HashSet::new();
for ci in ci_list.iter().chain(fixture_ci_list.iter()) {
for ci in self.iter_cis() {
if !set.insert(ci.namespace()) {
bail!("UDL files have duplicate namespace: {}", ci.namespace());
}
@ -54,22 +58,39 @@ impl ComponentInterfaceUniverse {
Ok(())
}
pub fn ci_list(&self) -> &Vec<ComponentInterface> {
&self.ci_list
fn check_callback_interfaces(&self) -> Result<()> {
// We don't currently support callback interfaces returning values or throwing errors.
for ci in self.iter_cis() {
for cbi in ci.callback_interface_definitions() {
for method in cbi.methods() {
if method.return_type().is_some() {
bail!("Callback interface method {}.{} throws an error, which is not yet supported", cbi.name(), method.name())
}
if method.throws_type().is_some() {
bail!("Callback interface method {}.{} returns a value, which is not yet supported", cbi.name(), method.name())
}
}
}
}
Ok(())
}
pub fn fixture_ci_list(&self) -> &Vec<ComponentInterface> {
&self.fixture_ci_list
}
pub fn iter_all(&self) -> impl Iterator<Item = &ComponentInterface> {
self.ci_list.iter().chain(self.fixture_ci_list.iter())
pub fn iter_cis(&self) -> impl Iterator<Item = &ComponentInterface> {
self.components
.iter()
.chain(self.fixture_components.iter())
.map(|(ci, _)| ci)
}
}
fn parse_udl_file(udl_file: Utf8PathBuf) -> Result<ComponentInterface> {
fn parse_udl_file(
udl_file: Utf8PathBuf,
config_map: &ConfigMap,
) -> Result<(ComponentInterface, Config)> {
let udl = std::fs::read_to_string(&udl_file).context("Error reading UDL file")?;
ComponentInterface::from_webidl(&udl).context("Failed to parse UDL")
let ci = ComponentInterface::from_webidl(&udl).context("Failed to parse UDL")?;
let config = config_map.get(ci.namespace()).cloned().unwrap_or_default();
Ok((ci, config))
}
pub struct FunctionIds<'a> {
@ -78,10 +99,10 @@ pub struct FunctionIds<'a> {
}
impl<'a> FunctionIds<'a> {
pub fn new(cis: &'a ComponentInterfaceUniverse) -> Self {
pub fn new(cis: &'a ComponentUniverse) -> Self {
Self {
map: cis
.iter_all()
.iter_cis()
.flat_map(|ci| {
ci.exposed_functions()
.into_iter()
@ -111,10 +132,10 @@ pub struct ObjectIds<'a> {
}
impl<'a> ObjectIds<'a> {
pub fn new(cis: &'a ComponentInterfaceUniverse) -> Self {
pub fn new(cis: &'a ComponentUniverse) -> Self {
Self {
map: cis
.iter_all()
.iter_cis()
.flat_map(|ci| {
ci.object_definitions()
.iter()
@ -137,3 +158,36 @@ impl<'a> ObjectIds<'a> {
format!("{}:{}", ci.namespace(), obj.name())
}
}
pub struct CallbackIds<'a> {
// Map (CI namespace, callback name) -> Ids
map: HashMap<(&'a str, &'a str), usize>,
}
impl<'a> CallbackIds<'a> {
pub fn new(cis: &'a ComponentUniverse) -> Self {
Self {
map: cis
.iter_cis()
.flat_map(|ci| {
ci.callback_interface_definitions()
.iter()
.map(move |cb| (ci.namespace(), cb.name()))
})
.enumerate()
.map(|(i, (namespace, name))| ((namespace, name), i))
// Sort using BTreeSet to guarantee the IDs remain stable across runs
.collect::<BTreeSet<_>>()
.into_iter()
.collect(),
}
}
pub fn get(&self, ci: &ComponentInterface, cb: &CallbackInterface) -> usize {
return *self.map.get(&(ci.namespace(), cb.name())).unwrap();
}
pub fn name(&self, ci: &ComponentInterface, cb: &CallbackInterface) -> String {
format!("{}:{}", ci.namespace(), cb.name())
}
}

Просмотреть файл

@ -6,16 +6,18 @@ use anyhow::{Context, Result};
use askama::Template;
use camino::Utf8PathBuf;
use clap::Parser;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::fs::File;
use std::io::Write;
use uniffi_bindgen::ComponentInterface;
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;
use ci_list::{CallbackIds, ComponentUniverse, FunctionIds, ObjectIds};
use render::cpp::CPPScaffoldingTemplate;
use render::js::JSBindingsTemplate;
#[derive(Debug, Parser)]
#[clap(name = "uniffi-bindgen-gecko-js")]
@ -44,6 +46,25 @@ struct CliArgs {
fixture_udl_files: Vec<Utf8PathBuf>,
}
/// Configuration for all components, read from `uniffi.toml`
type ConfigMap = HashMap<String, Config>;
/// Configuration for a single Component
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Config {
receiver_thread: ReceiverThreadConfig,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
struct ReceiverThreadConfig {
#[serde(default)]
default: Option<String>,
#[serde(default)]
main: HashSet<String>,
#[serde(default)]
worker: HashSet<String>,
}
fn render(out_path: Utf8PathBuf, template: impl Template) -> Result<()> {
println!("rendering {}", out_path);
let contents = template.render()?;
@ -55,32 +76,37 @@ fn render(out_path: Utf8PathBuf, template: impl Template) -> Result<()> {
fn render_cpp(
path: Utf8PathBuf,
prefix: &str,
ci_list: &Vec<ComponentInterface>,
components: &Vec<(ComponentInterface, Config)>,
function_ids: &FunctionIds,
object_ids: &ObjectIds,
callback_ids: &CallbackIds,
) -> Result<()> {
render(
path,
CPPScaffoldingTemplate {
prefix,
ci_list,
function_ids: &function_ids,
object_ids: &object_ids,
components,
function_ids,
object_ids,
callback_ids,
},
)
}
fn render_js(
out_dir: Utf8PathBuf,
ci_list: &Vec<ComponentInterface>,
components: &Vec<(ComponentInterface, Config)>,
function_ids: &FunctionIds,
object_ids: &ObjectIds,
callback_ids: &CallbackIds,
) -> Result<()> {
for ci in ci_list {
for (ci, config) in components {
let template = JSBindingsTemplate {
ci,
function_ids: &function_ids,
object_ids: &object_ids,
config,
function_ids,
object_ids,
callback_ids,
};
let path = out_dir.join(template.js_module_name());
render(path, template)?;
@ -90,30 +116,42 @@ fn render_js(
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);
let config_map: ConfigMap =
toml::from_str(include_str!("../config.toml")).expect("Error parsing config.toml");
let components = ComponentUniverse::new(args.udl_files, args.fixture_udl_files, config_map)?;
let function_ids = FunctionIds::new(&components);
let object_ids = ObjectIds::new(&components);
let callback_ids = CallbackIds::new(&components);
render_cpp(
args.cpp_path,
"UniFFI",
cis.ci_list(),
&components.components,
&function_ids,
&object_ids,
&callback_ids,
)?;
render_cpp(
args.fixture_cpp_path,
"UniFFIFixtures",
cis.fixture_ci_list(),
&components.fixture_components,
&function_ids,
&object_ids,
&callback_ids,
)?;
render_js(
args.js_dir,
&components.components,
&function_ids,
&object_ids,
&callback_ids,
)?;
render_js(args.js_dir, cis.ci_list(), &function_ids, &object_ids)?;
render_js(
args.fixture_js_dir,
cis.fixture_ci_list(),
&components.fixture_components,
&function_ids,
&object_ids,
&callback_ids,
)?;
Ok(())

Просмотреть файл

@ -2,13 +2,15 @@
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 crate::{CallbackIds, Config, FunctionIds, ObjectIds};
use askama::Template;
use extend::ext;
use heck::ToUpperCamelCase;
use heck::{ToShoutySnakeCase, ToUpperCamelCase};
use std::collections::HashSet;
use std::iter;
use uniffi_bindgen::interface::{ComponentInterface, FFIArgument, FFIFunction, FFIType, Object};
use uniffi_bindgen::interface::{
CallbackInterface, ComponentInterface, FFIArgument, FFIFunction, FFIType, Object,
};
#[derive(Template)]
#[template(path = "UniFFIScaffolding.cpp", escape = "none")]
@ -20,16 +22,17 @@ pub struct CPPScaffoldingTemplate<'a> {
// - 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<ComponentInterface>,
pub components: &'a Vec<(ComponentInterface, Config)>,
pub function_ids: &'a FunctionIds<'a>,
pub object_ids: &'a ObjectIds<'a>,
pub callback_ids: &'a CallbackIds<'a>,
}
impl<'a> CPPScaffoldingTemplate<'a> {
fn has_any_objects(&self) -> bool {
self.ci_list
self.components
.iter()
.any(|ci| ci.object_definitions().len() > 0)
.any(|(ci, _)| ci.object_definitions().len() > 0)
}
}
@ -63,6 +66,11 @@ pub impl ComponentInterface {
.object_definitions()
.iter()
.map(|o| o.ffi_object_free().name())
.chain(
self.callback_interface_definitions()
.iter()
.map(|cbi| cbi.ffi_init_callback().name()),
)
.collect();
self.iter_user_ffi_function_definitions()
.filter(move |f| !excluded.contains(f.name()))
@ -140,8 +148,8 @@ pub impl FFIType {
FFIType::Float64 => "double",
FFIType::RustBuffer => "RustBuffer",
FFIType::RustArcPtr(_) => "void *",
FFIType::ForeignCallback => "ForeignCallback",
FFIType::ForeignBytes => unimplemented!("ForeignBytes not supported"),
FFIType::ForeignCallback => unimplemented!("ForeignCallback not supported"),
}
.to_owned()
}
@ -160,3 +168,23 @@ pub impl Object {
self.name().to_upper_camel_case()
}
}
#[ext(name=CallbackInterfaceCppExt)]
pub impl CallbackInterface {
fn nm(&self) -> String {
self.name().to_upper_camel_case()
}
/// Name of the static pointer to the JS callback handler
fn js_handler(&self) -> String {
format!("JS_CALLBACK_HANDLER_{}", self.name().to_shouty_snake_case())
}
/// Name of the C function handler
fn c_handler(&self, prefix: &str) -> String {
format!(
"{prefix}CallbackHandler{}",
self.name().to_upper_camel_case()
)
}
}

Просмотреть файл

@ -3,13 +3,13 @@ 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 crate::{CallbackIds, Config, 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,
Argument, CallbackInterface, ComponentInterface, Constructor, Enum, Error, Field, Function,
Literal, Method, Object, Radix, Record, Type,
};
fn arg_names(args: &[&Argument]) -> String {
@ -42,8 +42,10 @@ fn render_enum_literal(typ: &Type, variant_name: &str) -> String {
#[template(path = "js/wrapper.jsm", escape = "none")]
pub struct JSBindingsTemplate<'a> {
pub ci: &'a ComponentInterface,
pub config: &'a Config,
pub function_ids: &'a FunctionIds<'a>,
pub object_ids: &'a ObjectIds<'a>,
pub callback_ids: &'a CallbackIds<'a>,
}
impl<'a> JSBindingsTemplate<'a> {
@ -130,12 +132,31 @@ pub impl Record {
}
}
#[ext(name=CallbackInterfaceJSExt)]
pub impl CallbackInterface {
fn nm(&self) -> String {
self.name().to_upper_camel_case()
}
fn handler(&self) -> String {
format!("callbackHandler{}", self.nm())
}
}
#[ext(name=FieldJSExt)]
pub impl Field {
fn nm(&self) -> String {
self.name().to_lower_camel_case()
}
fn lower_fn(&self) -> String {
self.type_().lower_fn()
}
fn lift_fn(&self) -> String {
self.type_().lift_fn()
}
fn write_datastream_fn(&self) -> String {
self.type_().write_datastream_fn()
}
@ -144,6 +165,10 @@ pub impl Field {
self.type_().read_datastream_fn()
}
fn compute_size_fn(&self) -> String {
self.type_().compute_size_fn()
}
fn ffi_converter(&self) -> String {
self.type_().ffi_converter()
}
@ -160,14 +185,34 @@ pub impl Field {
#[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 lower_fn(&self) -> String {
self.type_().lower_fn()
}
fn lift_fn(&self) -> String {
self.type_().lift_fn()
}
fn write_datastream_fn(&self) -> String {
self.type_().write_datastream_fn()
}
fn read_datastream_fn(&self) -> String {
self.type_().read_datastream_fn()
}
fn compute_size_fn(&self) -> String {
self.type_().compute_size_fn()
}
fn ffi_converter(&self) -> String {
self.type_().ffi_converter()
}
fn check_type(&self) -> String {
format!(
"{}.checkType(\"{}\", {})",
@ -188,6 +233,14 @@ pub impl Type {
}
}
fn lower_fn(&self) -> String {
format!("{}.lower", self.ffi_converter())
}
fn lift_fn(&self) -> String {
format!("{}.lift", self.ffi_converter())
}
fn write_datastream_fn(&self) -> String {
format!("{}.write", self.ffi_converter())
}
@ -196,6 +249,10 @@ pub impl Type {
format!("{}.read", self.ffi_converter())
}
fn compute_size_fn(&self) -> String {
format!("{}.computeSize", self.ffi_converter())
}
fn ffi_converter(&self) -> String {
format!(
"FfiConverter{}",

Просмотреть файл

@ -3,37 +3,37 @@ 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 crate::Config;
use extend::ext;
use uniffi_bindgen::interface::{Constructor, FFIFunction, Function, Method};
use uniffi_bindgen::interface::{Function, Method, Object};
#[ext]
pub impl FFIFunction {
fn is_async(&self) -> bool {
// TODO check `uniffi.toml` or some other configuration to figure this out
fn is_async(config: &Config, spec: &str) -> bool {
if config.receiver_thread.main.contains(spec) {
false
} else if config.receiver_thread.worker.contains(spec) {
true
} else {
match &config.receiver_thread.default {
Some(t) => t != "main",
_ => true,
}
}
}
#[ext]
pub impl Function {
fn is_async(&self) -> bool {
// TODO check `uniffi.toml` or some other configuration to figure this out
true
fn is_async(&self, config: &Config) -> bool {
is_async(config, self.name())
}
}
#[ext]
pub impl Constructor {
fn is_async(&self) -> bool {
// TODO check `uniffi.toml` or some other configuration to figure this out
true
pub impl Object {
fn is_constructor_async(&self, config: &Config) -> bool {
is_async(config, self.name())
}
}
#[ext]
pub impl Method {
fn is_async(&self) -> bool {
// TODO check `uniffi.toml` or some other configuration to figure this out
true
fn is_method_async(&self, method: &Method, config: &Config) -> bool {
is_async(config, &format!("{}.{}", self.name(), method.name()))
}
}

Просмотреть файл

@ -2,24 +2,29 @@
#include "nsString.h"
#include "nsPrintfCString.h"
#include "mozilla/Logging.h"
#include "mozilla/Maybe.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/dom/UniFFICallbacks.h"
#include "mozilla/dom/UniFFIScaffolding.h"
#include "mozilla/dom/ScaffoldingCall.h"
namespace mozilla::uniffi {
using dom::ArrayBuffer;
using dom::AutoEntryScript;
using dom::GlobalObject;
using dom::RootedDictionary;
using dom::Promise;
using dom::ScaffoldingType;
using dom::Sequence;
using dom::UniFFICallbackHandler;
using dom::UniFFIPointer;
using dom::UniFFIScaffoldingCallResult;
// Define scaffolding functions from UniFFI
extern "C" {
{%- for ci in ci_list %}
{%- for (ci, config) in components %}
{%- for func in ci.iter_user_ffi_function_definitions() %}
{{ func.rust_return_type() }} {{ func.rust_name() }}({{ func.rust_arg_list() }});
{%- endfor %}
@ -27,20 +32,57 @@ extern "C" {
}
// Define pointer types
{%- for ci in ci_list %}
{%- for (ci, config) in components %}
{%- 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 %}
// Define the data we need per-callback interface
{%- for (ci, config) in components %}
{%- for cbi in ci.callback_interface_definitions() %}
MOZ_CAN_RUN_SCRIPT
extern "C" int {{ cbi.c_handler(prefix) }}(uint64_t aHandle, uint32_t aMethod, RustBuffer aArgs, RustBuffer* aOutBuffer) {
// Currently, we only support "fire-and-forget" async callbacks. These are
// callbacks that run asynchronously without returning anything. The main
// use case for callbacks is logging, which fits very well with this model.
//
// So, here we simple queue the callback and return immediately.
mozilla::uniffi::QueueCallback({{ callback_ids.get(ci, cbi) }}, aHandle, aMethod, aArgs);
return CALLBACK_INTERFACE_SUCCESS;
}
static StaticRefPtr<dom::UniFFICallbackHandler> {{ cbi.js_handler() }};
{%- endfor %}
{%- endfor %}
// Define a lookup function for our callback interface info
Maybe<CallbackInterfaceInfo> {{ prefix }}GetCallbackInterfaceInfo(uint64_t aInterfaceId) {
switch(aInterfaceId) {
{%- for (ci, config) in components %}
{%- for cbi in ci.callback_interface_definitions() %}
case {{ callback_ids.get(ci, cbi) }}: { // {{ callback_ids.name(ci, cbi) }}
return Some(CallbackInterfaceInfo {
"{{ cbi.name() }}",
&{{ cbi.js_handler() }},
{{ cbi.c_handler(prefix) }},
{{ cbi.ffi_init_callback().name() }},
});
}
{%- endfor %}
{%- endfor %}
default:
return Nothing();
}
}
Maybe<already_AddRefed<Promise>> {{ prefix }}CallAsync(const GlobalObject& aGlobal, uint64_t aId, const Sequence<ScaffoldingType>& aArgs, ErrorResult& aError) {
switch (aId) {
{%- for ci in ci_list %}
{%- for (ci, config) in components %}
{%- for func in ci.exposed_functions() %}
case {{ function_ids.get(ci, func) }}: { // {{ function_ids.name(ci, func) }}
using CallHandler = {{ ci.scaffolding_call_handler(func) }};
@ -54,7 +96,7 @@ Maybe<already_AddRefed<Promise>> {{ prefix }}CallAsync(const GlobalObject& aGlob
bool {{ prefix }}CallSync(const GlobalObject& aGlobal, uint64_t aId, const Sequence<ScaffoldingType>& aArgs, RootedDictionary<UniFFIScaffoldingCallResult>& aReturnValue, ErrorResult& aError) {
switch (aId) {
{%- for ci in ci_list %}
{%- for (ci, config) in components %}
{%- for func in ci.exposed_functions() %}
case {{ function_ids.get(ci, func) }}: { // {{ function_ids.name(ci, func) }}
using CallHandler = {{ ci.scaffolding_call_handler(func) }};
@ -71,7 +113,7 @@ Maybe<already_AddRefed<UniFFIPointer>> {{ prefix }}ReadPointer(const GlobalObjec
{%- if self.has_any_objects() %}
const UniFFIPointerType* type;
switch (aId) {
{%- for ci in ci_list %}
{%- for (ci, config) in components %}
{%- for object in ci.object_definitions() %}
case {{ object_ids.get(ci, object) }}: { // {{ object_ids.name(ci, object) }}
type = &{{ ci.pointer_type(object) }};
@ -92,7 +134,7 @@ bool {{ prefix }}WritePointer(const GlobalObject& aGlobal, uint64_t aId, const U
{%- if self.has_any_objects() %}
const UniFFIPointerType* type;
switch (aId) {
{%- for ci in ci_list %}
{%- for (ci, config) in components %}
{%- for object in ci.object_definitions() %}
case {{ object_ids.get(ci, object) }}: { // {{ object_ids.name(ci, object) }}
type = &{{ ci.pointer_type(object) }};

Просмотреть файл

@ -0,0 +1,23 @@
{%- let cbi = ci.get_callback_interface_definition(name).unwrap() %}
{#- See CallbackInterfaceRuntime.jsm and CallbackInterfaceHandler.jsm for the callback interface handler definition, referenced here as `{{ cbi.handler() }}` #}
class {{ ffi_converter }} extends FfiConverter {
static lower(callbackObj) {
return {{ cbi.handler() }}.storeCallbackObj(callbackObj)
}
static lift(handleId) {
return {{ cbi.handler() }}.getCallbackObj(handleId)
}
static read(dataStream) {
return this.lift(dataStream.readInt64())
}
static write(dataStream, callbackObj) {
dataStream.writeInt64(this.lower(callbackObj))
}
static computeSize(callbackObj) {
return 8;
}
}

Просмотреть файл

@ -0,0 +1,19 @@
const {{ cbi.handler() }} = new UniFFICallbackHandler(
"{{ callback_ids.name(ci, cbi) }}",
{{ callback_ids.get(ci, cbi) }},
[
{%- for method in cbi.methods() %}
new UniFFICallbackMethodHandler(
"{{ method.nm() }}",
[
{%- for arg in method.arguments() %}
{{ arg.ffi_converter() }},
{%- endfor %}
],
),
{%- endfor %}
]
);
// Allow the shutdown-related functionality to be tested in the unit tests
UnitTestObjs.{{ cbi.handler() }} = {{ cbi.handler() }};

Просмотреть файл

@ -0,0 +1,195 @@
/**
* Handler for a single UniFFI CallbackInterface
*
* This class stores objects that implement a callback interface in a handle
* map, allowing them to be referenced by the Rust code using an integer
* handle.
*
* While the callback object is stored in the map, it allows the Rust code to
* call methods on the object using the callback object handle, a method id,
* and an ArrayBuffer packed with the method arguments.
*
* When the Rust code drops its reference, it sends a call with the methodId=0,
* which causes callback object to be removed from the map.
*/
class UniFFICallbackHandler {
#name;
#interfaceId;
#handleCounter;
#handleMap;
#methodHandlers;
#allowNewCallbacks
/**
* Create a UniFFICallbackHandler
* @param {string} name - Human-friendly name for this callback interface
* @param {int} interfaceId - Interface ID for this CallbackInterface.
* @param {UniFFICallbackMethodHandler[]} methodHandlers -- UniFFICallbackHandler for each method, in the same order as the UDL file
*/
constructor(name, interfaceId, methodHandlers) {
this.#name = name;
this.#interfaceId = interfaceId;
this.#handleCounter = 0;
this.#handleMap = new Map();
this.#methodHandlers = methodHandlers;
this.#allowNewCallbacks = true;
UniFFIScaffolding.registerCallbackHandler(this.#interfaceId, this.invokeCallback.bind(this));
Services.obs.addObserver(this, "xpcom-shutdown");
}
/**
* Store a callback object in the handle map and return the handle
*
* @param {obj} callbackObj - Object that implements the callback interface
* @returns {int} - Handle for this callback object, this is what gets passed back to Rust.
*/
storeCallbackObj(callbackObj) {
if (!this.#allowNewCallbacks) {
throw new UniFFIError(`No new callbacks allowed for ${this.#name}`);
}
const handle = this.#handleCounter;
this.#handleCounter += 1;
this.#handleMap.set(handle, new UniFFICallbackHandleMapEntry(callbackObj, Components.stack.caller.formattedStack.trim()));
return handle;
}
/**
* Get a previously stored callback object
*
* @param {int} handle - Callback object handle, returned from `storeCallbackObj()`
* @returns {obj} - Callback object
*/
getCallbackObj(handle) {
return this.#handleMap.get(handle).callbackObj;
}
/**
* Set if new callbacks are allowed for this handler
*
* This is called with false during shutdown to ensure the callback maps don't
* prevent JS objects from being GCed.
*/
setAllowNewCallbacks(allow) {
this.#allowNewCallbacks = allow
}
/**
* Check that no callbacks are currently registered
*
* If there are callbacks registered a UniFFIError will be thrown. This is
* called during shutdown to generate an alert if there are leaked callback
* interfaces.
*/
assertNoRegisteredCallbacks() {
if (this.#handleMap.size > 0) {
const entry = this.#handleMap.values().next().value;
throw new UniFFIError(`UniFFI interface ${this.#name} has ${this.#handleMap.size} registered callbacks at xpcom-shutdown. This likely indicates a UniFFI callback leak.\nStack trace for the first leaked callback:\n${entry.stackTrace}.`);
}
}
/**
* Invoke a method on a stored callback object
* @param {int} handle - Object handle
* @param {int} methodId - Method identifier. This the 1-based index of
* the method from the UDL file. 0 is the special drop method, which
* removes the callback object from the handle map.
* @param {ArrayBuffer} argsArrayBuffer - Arguments to pass to the method, packed in an ArrayBuffer
*/
invokeCallback(handle, methodId, argsArrayBuffer) {
try {
this.#invokeCallbackInner(handle, methodId, argsArrayBuffer);
} catch (e) {
console.error(`internal error invoking callback: ${e}`)
}
}
#invokeCallbackInner(handle, methodId, argsArrayBuffer) {
const callbackObj = this.getCallbackObj(handle);
if (callbackObj === undefined) {
throw new UniFFIError(`${this.#name}: invalid callback handle id: ${handle}`);
}
// Special-cased drop method, remove the object from the handle map and
// return an empty array buffer
if (methodId == 0) {
this.#handleMap.delete(handle);
return;
}
// Get the method data, converting from 1-based indexing
const methodHandler = this.#methodHandlers[methodId - 1];
if (methodHandler === undefined) {
throw new UniFFIError(`${this.#name}: invalid method id: ${methodId}`)
}
methodHandler.call(callbackObj, argsArrayBuffer);
}
/**
* xpcom-shutdown observer method
*
* This handles:
* - Deregistering ourselves as the UniFFI callback handler
* - Checks for any leftover stored callbacks which indicate memory leaks
*/
observe(aSubject, aTopic, aData) {
if (aTopic == "xpcom-shutdown") {
try {
this.setAllowNewCallbacks(false);
this.assertNoRegisteredCallbacks();
UniFFIScaffolding.deregisterCallbackHandler(this.#interfaceId);
} catch (ex) {
console.error(`UniFFI Callback interface error during xpcom-shutdown: ${ex}`);
Cc["@mozilla.org/xpcom/debug;1"]
.getService(Ci.nsIDebug2)
.abort(ex.filename, ex.lineNumber);
}
}
}
}
/**
* Handles calling a single method for a callback interface
*/
class UniFFICallbackMethodHandler {
#name;
#argsConverters;
/**
* Create a UniFFICallbackMethodHandler
* @param {string} name -- Name of the method to call on the callback object
* @param {FfiConverter[]} argsConverters - FfiConverter for each argument type
*/
constructor(name, argsConverters) {
this.#name = name;
this.#argsConverters = argsConverters;
}
/**
* Invoke the method
*
* @param {obj} callbackObj -- Object implementing the callback interface for this method
* @param {ArrayBuffer} argsArrayBuffer -- Arguments for the method, packed in an ArrayBuffer
*/
call(callbackObj, argsArrayBuffer) {
const argsStream = new ArrayBufferDataStream(argsArrayBuffer);
const args = this.#argsConverters.map(converter => converter.read(argsStream));
callbackObj[this.#name](...args);
}
}
/**
* UniFFICallbackHandler.handleMap entry
*
* @property callbackObj - Callback object, this must implement the callback interface.
* @property {string} stackTrace - Stack trace from when the callback object was registered. This is used to proved extra context when debugging leaked callback objects.
*/
class UniFFICallbackHandleMapEntry {
constructor(callbackObj, stackTrace) {
this.callbackObj = callbackObj;
this.stackTrace = stackTrace
}
}

Просмотреть файл

@ -18,16 +18,19 @@ class {{ variant.name().to_upper_camel_case() }} extends {{ error.nm() }} {
{{field.nm()}},
{% endfor -%}
...params
) {
super(...params);
{%- for field in variant.fields() %}
this.{{field.nm()}} = {{ field.nm() }};
{%- endfor %}
}
) {
super(...params);
{%- for field in variant.fields() %}
this.{{field.nm()}} = {{ field.nm() }};
{%- endfor %}
}
{%- endif %}
toString() {
return `{{ variant.name().to_upper_camel_case() }}: ${super.toString()}`
}
}
EXPORTED_SYMBOLS.push("{{ variant.name().to_upper_camel_case() }}");
{%-endfor %}
{%- endfor %}
class {{ ffi_converter }} extends FfiConverterArrayBuffer {
static read(dataStream) {
@ -45,7 +48,34 @@ class {{ ffi_converter }} extends FfiConverterArrayBuffer {
{%- endif %}
{%- endfor %}
default:
return new Error("Unknown {{ error.nm() }} variant");
throw new Error("Unknown {{ error.nm() }} variant");
}
}
static computeSize(value) {
// Size of the Int indicating the variant
let totalSize = 4;
{%- for variant in error.variants() %}
if (value instanceof {{ variant.name().to_upper_camel_case() }}) {
{%- for field in variant.fields() %}
totalSize += {{ field.ffi_converter() }}.computeSize(value.{{ field.nm() }});
{%- endfor %}
return totalSize;
}
{%- endfor %}
throw new Error("Unknown {{ error.nm() }} variant");
}
static write(dataStream, value) {
{%- for variant in error.variants() %}
if (value instanceof {{ 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 %}
throw new Error("Unknown {{ error.nm() }} variant");
}
static errorClass = {{ error.nm() }};
}

Просмотреть файл

@ -94,7 +94,6 @@ class ArrayBufferDataStream {
this.pos += 8;
}
readFloat32() {
let rv = this.dataView.getFloat32(this.pos);
this.pos += 4;
@ -193,6 +192,10 @@ class UniFFIError {
constructor(message) {
this.message = message;
}
toString() {
return `UniFFIError: ${this.message}`
}
}
class UniFFIInternalError extends UniFFIError {}

Просмотреть файл

@ -14,7 +14,7 @@ class {{ object.nm() }} {
}
{%- for cons in object.constructors() %}
{%- if cons.is_async() %}
{%- if object.is_constructor_async(config) %}
/**
* An async constructor for {{ object.nm() }}.
*
@ -29,13 +29,14 @@ class {{ object.nm() }} {
*/
{%- endif %}
static {{ cons.nm() }}({{cons.arg_names()}}) {
{%- call js::call_constructor(cons, type_) -%}
{%- call js::call_constructor(cons, type_, object.is_constructor_async(config)) -%}
}
{%- endfor %}
{%- for meth in object.methods() %}
{{ meth.nm() }}({{ meth.arg_names() }}) {
{%- call js::call_method(meth, type_, object) -%}
{%- call js::call_method(meth, type_, object.is_method_async(meth, config)) %}
}
{%- endfor %}

Просмотреть файл

@ -33,4 +33,3 @@ class {{ ffi_converter }} extends FfiConverterArrayBuffer {
return 1 + {{ inner.ffi_converter() }}.computeSize(value)
}
}

Просмотреть файл

@ -1,3 +1,8 @@
{%- if !ci.callback_interface_definitions().is_empty() %}
{%- include "CallbackInterfaceRuntime.jsm" %}
{% endif %}
{%- for type_ in ci.iter_types() %}
{%- let ffi_converter = type_.ffi_converter() %}
{%- match type_ %}
@ -65,6 +70,9 @@
{%- when Type::External with { name, crate_name } %}
{%- include "ExternalType.jsm" %}
{%- when Type::CallbackInterface with (name) %}
{%- include "CallbackInterface.jsm" %}
{%- else %}
{#- TODO implement the other types #}
@ -74,3 +82,11 @@
EXPORTED_SYMBOLS.push("{{ ffi_converter }}");
{% endfor %}
{%- if !ci.callback_interface_definitions().is_empty() %}
// Define callback interface handlers, this must come after the type loop since they reference the FfiConverters defined above.
{% for cbi in ci.callback_interface_definitions() %}
{%- include "CallbackInterfaceHandler.jsm" %}
{% endfor %}
{% endif %}

Просмотреть файл

@ -1,55 +1,55 @@
{%- macro call_scaffolding_function(func) %}
{%- call _call_scaffolding_function(func, func.return_type(), "") -%}
{%- call _call_scaffolding_function(func, func.return_type(), "", func.is_async(config)) -%}
{%- endmacro %}
{%- macro call_constructor(cons, object_type) %}
{%- call _call_scaffolding_function(cons, Some(object_type), "") -%}
{%- macro call_constructor(cons, object_type, is_async) %}
{%- call _call_scaffolding_function(cons, Some(object_type), "", is_async) -%}
{%- endmacro %}
{%- macro call_method(method, object_type) %}
{%- call _call_scaffolding_function(method, method.return_type(), object_type.ffi_converter()) -%}
{%- macro call_method(method, object_type, is_async) %}
{%- call _call_scaffolding_function(method, method.return_type(), object_type.ffi_converter(), is_async) -%}
{%- 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(
{%- macro _call_scaffolding_function(func, return_type, receiver_ffi_converter, is_async) %}
{%- match return_type %}
{%- when Some with (return_type) %}
const liftResult = (result) => {{ return_type.ffi_converter() }}.lift(result);
{%- 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 %}
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.lower_fn_name() }}({{ arg.nm() }}),
{{ arg.check_type() }};
{%- 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 %}
{%- if 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() }}({{ arg.nm() }}),
{%- endfor %}
)
}
{%- if 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 %}

Просмотреть файл

@ -5,7 +5,10 @@
"use strict";
var EXPORTED_SYMBOLS = [];
// Objects intended to be used in the unit tests
var UnitTestObjs = {};
var EXPORTED_SYMBOLS = ["UnitTestObjs"];
{% include "Helpers.jsm" %}

Просмотреть файл

@ -0,0 +1,15 @@
[package]
name = "uniffi-fixture-callbacks"
edition = "2021"
version = "0.21.0"
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
license = "MPL-2.0"
publish = false
[dependencies]
uniffi_macros = "0.21"
uniffi = "0.21"
thiserror = "1.0"
[build-dependencies]
uniffi_build = "0.21"

Просмотреть файл

@ -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/. */
fn main() {
uniffi_build::generate_scaffolding("./src/callbacks.udl").unwrap();
}

Просмотреть файл

@ -0,0 +1,12 @@
callback interface Logger {
void log(string message);
void finished();
};
namespace fixture_callbacks {
// Log all even numbers in a vec, then call the finished() method
void log_even_numbers(Logger logger, sequence<i32> items);
// Works exactly the same as `log_even_numbers()`, except we configure this
// to run on the main thread in `uniffi-bindgen-gecko-js/config.toml`
void log_even_numbers_main_thread(Logger logger, sequence<i32> items);
};

Просмотреть файл

@ -0,0 +1,23 @@
/* 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/. */
trait Logger {
fn log(&self, message: String);
fn finished(&self);
}
fn log_even_numbers(logger: Box<dyn Logger>, items: Vec<i32>) {
for i in items {
if i % 2 == 0 {
logger.log(format!("Saw even number: {i}"))
}
}
logger.finished();
}
fn log_even_numbers_main_thread(logger: Box<dyn Logger>, items: Vec<i32>) {
log_even_numbers(logger, items)
}
include!(concat!(env!("OUT_DIR"), "/callbacks.uniffi.rs"));

Просмотреть файл

@ -7,7 +7,7 @@ license = "MPL-2.0"
publish = false
[dependencies]
uniffi-example-geometry = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "bb2039f077a29dba0879372a67e764e6ace8e33f" }
uniffi-example-geometry = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "846612a1d4fb5d11e246bf0682da4a499409424c" }
uniffi_macros = "0.21"
uniffi = "0.21"
thiserror = "1.0"

Просмотреть файл

@ -0,0 +1,137 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsPrintfCString.h"
#include "nsString.h"
#include "nsThreadUtils.h"
#include "mozilla/dom/OwnedRustBuffer.h"
#include "mozilla/dom/RootedDictionary.h"
#include "mozilla/dom/UniFFIBinding.h"
#include "mozilla/dom/UniFFICallbacks.h"
#include "mozilla/Maybe.h"
#include "mozilla/Logging.h"
#include "mozilla/RefPtr.h"
static mozilla::LazyLogModule UNIFFI_INVOKE_CALLBACK_LOGGER("uniffi");
namespace mozilla::uniffi {
using dom::ArrayBuffer;
using dom::RootedDictionary;
using dom::UniFFICallbackHandler;
using dom::UniFFIScaffoldingCallCode;
static Maybe<CallbackInterfaceInfo> GetCallbackInterfaceInfo(
uint64_t aInterfaceId) {
const Maybe<CallbackInterfaceInfo> cbiInfo =
UniFFIGetCallbackInterfaceInfo(aInterfaceId);
#ifdef MOZ_UNIFFI_FIXTURES
if (!cbiInfo) {
return UniFFIFixturesGetCallbackInterfaceInfo(aInterfaceId);
}
#endif
return cbiInfo;
}
void RegisterCallbackHandler(uint64_t aInterfaceId,
UniFFICallbackHandler& aCallbackHandler,
ErrorResult& aError) {
// We should only be mutating mHandler on the main thread
MOZ_ASSERT(NS_IsMainThread());
Maybe<CallbackInterfaceInfo> cbiInfo = GetCallbackInterfaceInfo(aInterfaceId);
if (!cbiInfo.isSome()) {
aError.ThrowUnknownError(
nsPrintfCString("Unknown interface id: %" PRIu64, aInterfaceId));
return;
}
if (*cbiInfo->mHandler) {
MOZ_LOG(UNIFFI_INVOKE_CALLBACK_LOGGER, LogLevel::Error,
("[UniFFI] Callback handler already registered for %s",
cbiInfo->mName));
return;
}
*cbiInfo->mHandler = &aCallbackHandler;
RustCallStatus status = {0};
cbiInfo->mInitForeignCallback(cbiInfo->mForeignCallback, &status);
// Just use MOZ_DIAGNOSTIC_ASSERT to check the status, since the call should
// always succeed. The RustCallStatus out param only exists because UniFFI
// adds it to all FFI calls.
MOZ_DIAGNOSTIC_ASSERT(status.code == RUST_CALL_SUCCESS);
}
void DeregisterCallbackHandler(uint64_t aInterfaceId, ErrorResult& aError) {
// We should only be mutating mHandler on the main thread
MOZ_ASSERT(NS_IsMainThread());
Maybe<CallbackInterfaceInfo> cbiInfo = GetCallbackInterfaceInfo(aInterfaceId);
if (!cbiInfo.isSome()) {
aError.ThrowUnknownError(
nsPrintfCString("Unknown interface id: %" PRIu64, aInterfaceId));
return;
}
*cbiInfo->mHandler = nullptr;
}
MOZ_CAN_RUN_SCRIPT
static void QueueCallbackInner(uint64_t aInterfaceId, uint64_t aHandle,
uint32_t aMethod, OwnedRustBuffer aArgs) {
MOZ_ASSERT(NS_IsMainThread());
Maybe<CallbackInterfaceInfo> cbiInfo = GetCallbackInterfaceInfo(aInterfaceId);
if (!cbiInfo.isSome()) {
MOZ_LOG(UNIFFI_INVOKE_CALLBACK_LOGGER, LogLevel::Error,
("[UniFFI] Unknown inferface id: %" PRIu64, aInterfaceId));
return;
}
// Take our own reference to the callback handler to ensure that it stays
// alive for the duration of this call
RefPtr<UniFFICallbackHandler> ihandler = *cbiInfo->mHandler;
if (!ihandler) {
MOZ_LOG(UNIFFI_INVOKE_CALLBACK_LOGGER, LogLevel::Error,
("[UniFFI] JS handler for %s not registered", cbiInfo->mName));
return;
}
JSObject* global = ihandler->CallbackGlobalOrNull();
if (!global) {
MOZ_LOG(UNIFFI_INVOKE_CALLBACK_LOGGER, LogLevel::Error,
("[UniFFI] JS handler for %s has null global", cbiInfo->mName));
return;
}
dom::AutoEntryScript aes(global, cbiInfo->mName);
IgnoredErrorResult error;
JS::Rooted<JSObject*> args(aes.cx(), aArgs.IntoArrayBuffer(aes.cx()));
ihandler->Call(aHandle, aMethod, args, error);
if (error.Failed()) {
MOZ_LOG(UNIFFI_INVOKE_CALLBACK_LOGGER, LogLevel::Error,
("[UniFFI] Error invoking JS handler for %s", cbiInfo->mName));
return;
}
}
void QueueCallback(uint64_t aInterfaceId, uint64_t aHandle, uint32_t aMethod,
RustBuffer aArgs) {
nsresult dispatchResult =
GetMainThreadSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
"UniFFI callback", [=]() MOZ_CAN_RUN_SCRIPT_BOUNDARY {
QueueCallbackInner(aInterfaceId, aHandle, aMethod,
OwnedRustBuffer(aArgs));
}));
if (NS_FAILED(dispatchResult)) {
MOZ_LOG(UNIFFI_INVOKE_CALLBACK_LOGGER, LogLevel::Error,
("[UniFFI] Error dispatching UniFFI callback task"));
}
}
} // namespace mozilla::uniffi

Просмотреть файл

@ -0,0 +1,75 @@
/* -*- 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_UniFFICallbacks_h
#define mozilla_UniFFICallbacks_h
#include "mozilla/StaticPtr.h"
#include "mozilla/dom/UniFFIRust.h"
#include "mozilla/dom/UniFFIScaffolding.h"
namespace mozilla::uniffi {
/**
* UniFFI-generated scaffolding function to initialize a callback interface
*
* The Rust code expests us to pass it a ForeignCallback entrypoint for each
* callback interface.
*/
typedef void (*CallbackInitFunc)(ForeignCallback, RustCallStatus*);
/**
* All the information needed to handle a callback interface.
*
* The generated code includes a function that maps interface ids to one of
* these structs
*/
struct CallbackInterfaceInfo {
// Human-friendly name
const char* mName;
// JS handler
StaticRefPtr<dom::UniFFICallbackHandler>* mHandler;
// Handler function, defined in the generated C++ code
ForeignCallback mForeignCallback;
// Init function, defined in the generated Rust scaffolding. mForeignCallback
// should be passed to this.
CallbackInitFunc mInitForeignCallback;
};
Maybe<CallbackInterfaceInfo> UniFFIGetCallbackInterfaceInfo(
uint64_t aInterfaceId);
#ifdef MOZ_UNIFFI_FIXTURES
Maybe<CallbackInterfaceInfo> UniFFIFixturesGetCallbackInterfaceInfo(
uint64_t aInterfaceId);
#endif
/**
* Register the JS handler for a callback interface
*/
void RegisterCallbackHandler(uint64_t aInterfaceId,
dom::UniFFICallbackHandler& aCallbackHandler,
ErrorResult& aError);
/**
* Deregister the JS handler for a callback interface
*/
void DeregisterCallbackHandler(uint64_t aInterfaceId, ErrorResult& aError);
/**
* Queue a UniFFI callback interface function to run at some point
*
* This function is for fire-and-forget callbacks where the caller doesn't care
* about the return value and doesn't want to wait for the call to finish. A
* good use case for this is logging.
*/
MOZ_CAN_RUN_SCRIPT
void QueueCallback(size_t aInterfaceId, uint64_t aHandle, uint32_t aMethod,
RustBuffer aArgs);
} // namespace mozilla::uniffi
#endif // mozilla_UniFFICallbacks_h

Просмотреть файл

@ -2,18 +2,23 @@
#include "nsString.h"
#include "nsPrintfCString.h"
#include "mozilla/Logging.h"
#include "mozilla/Maybe.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/dom/UniFFICallbacks.h"
#include "mozilla/dom/UniFFIScaffolding.h"
#include "mozilla/dom/ScaffoldingCall.h"
namespace mozilla::uniffi {
using dom::ArrayBuffer;
using dom::AutoEntryScript;
using dom::GlobalObject;
using dom::RootedDictionary;
using dom::Promise;
using dom::ScaffoldingType;
using dom::Sequence;
using dom::UniFFICallbackHandler;
using dom::UniFFIPointer;
using dom::UniFFIScaffoldingCallResult;
@ -111,6 +116,9 @@ extern "C" {
RustBuffer todolist_aa33_get_default_list(RustCallStatus*);
void todolist_aa33_set_default_list(void *, RustCallStatus*);
RustBuffer todolist_aa33_create_entry_with(RustBuffer, RustCallStatus*);
void ffi_fixture_callbacks_1107_Logger_init_callback(ForeignCallback, RustCallStatus*);
void fixture_callbacks_1107_log_even_numbers(uint64_t, RustBuffer, RustCallStatus*);
void fixture_callbacks_1107_log_even_numbers_main_thread(uint64_t, RustBuffer, RustCallStatus*);
RustBuffer custom_types_8ecd_get_custom_types_demo(RustBuffer, RustCallStatus*);
double external_types_54cc_gradient(RustBuffer, RustCallStatus*);
}
@ -137,6 +145,36 @@ const static mozilla::uniffi::UniFFIPointerType kTodolistTodoListPointerType {
ffi_todolist_aa33_TodoList_object_free
};
// Define the data we need per-callback interface
MOZ_CAN_RUN_SCRIPT
extern "C" int UniFFIFixturesCallbackHandlerLogger(uint64_t aHandle, uint32_t aMethod, RustBuffer aArgs, RustBuffer* aOutBuffer) {
// Currently, we only support "fire-and-forget" async callbacks. These are
// callbacks that run asynchronously without returning anything. The main
// use case for callbacks is logging, which fits very well with this model.
//
// So, here we simple queue the callback and return immediately.
mozilla::uniffi::QueueCallback(0, aHandle, aMethod, aArgs);
return CALLBACK_INTERFACE_SUCCESS;
}
static StaticRefPtr<dom::UniFFICallbackHandler> JS_CALLBACK_HANDLER_LOGGER;
// Define a lookup function for our callback interface info
Maybe<CallbackInterfaceInfo> UniFFIFixturesGetCallbackInterfaceInfo(uint64_t aInterfaceId) {
switch(aInterfaceId) {
case 0: { // fixture_callbacks:Logger
return Some(CallbackInterfaceInfo {
"Logger",
&JS_CALLBACK_HANDLER_LOGGER,
UniFFIFixturesCallbackHandlerLogger,
ffi_fixture_callbacks_1107_Logger_init_callback,
});
}
default:
return Nothing();
}
}
Maybe<already_AddRefed<Promise>> UniFFIFixturesCallAsync(const GlobalObject& aGlobal, uint64_t aId, const Sequence<ScaffoldingType>& aArgs, ErrorResult& aError) {
switch (aId) {
case 20: { // geometry:geometry_1cce_gradient
@ -487,11 +525,19 @@ Maybe<already_AddRefed<Promise>> UniFFIFixturesCallAsync(const GlobalObject& aGl
using CallHandler = ScaffoldingCallHandler<ScaffoldingConverter<RustBuffer>, ScaffoldingConverter<RustBuffer>>;
return Some(CallHandler::CallAsync(todolist_aa33_create_entry_with, aGlobal, aArgs, "todolist_aa33_create_entry_with: "_ns, aError));
}
case 107: { // custom_types:custom_types_8ecd_get_custom_types_demo
case 107: { // fixture_callbacks:fixture_callbacks_1107_log_even_numbers
using CallHandler = ScaffoldingCallHandler<ScaffoldingConverter<void>, ScaffoldingConverter<uint64_t>, ScaffoldingConverter<RustBuffer>>;
return Some(CallHandler::CallAsync(fixture_callbacks_1107_log_even_numbers, aGlobal, aArgs, "fixture_callbacks_1107_log_even_numbers: "_ns, aError));
}
case 108: { // fixture_callbacks:fixture_callbacks_1107_log_even_numbers_main_thread
using CallHandler = ScaffoldingCallHandler<ScaffoldingConverter<void>, ScaffoldingConverter<uint64_t>, ScaffoldingConverter<RustBuffer>>;
return Some(CallHandler::CallAsync(fixture_callbacks_1107_log_even_numbers_main_thread, aGlobal, aArgs, "fixture_callbacks_1107_log_even_numbers_main_thread: "_ns, aError));
}
case 109: { // custom_types:custom_types_8ecd_get_custom_types_demo
using CallHandler = ScaffoldingCallHandler<ScaffoldingConverter<RustBuffer>, ScaffoldingConverter<RustBuffer>>;
return Some(CallHandler::CallAsync(custom_types_8ecd_get_custom_types_demo, aGlobal, aArgs, "custom_types_8ecd_get_custom_types_demo: "_ns, aError));
}
case 108: { // external_types:external_types_54cc_gradient
case 110: { // external_types:external_types_54cc_gradient
using CallHandler = ScaffoldingCallHandler<ScaffoldingConverter<double>, ScaffoldingConverter<RustBuffer>>;
return Some(CallHandler::CallAsync(external_types_54cc_gradient, aGlobal, aArgs, "external_types_54cc_gradient: "_ns, aError));
}
@ -936,12 +982,22 @@ bool UniFFIFixturesCallSync(const GlobalObject& aGlobal, uint64_t aId, const Seq
CallHandler::CallSync(todolist_aa33_create_entry_with, aGlobal, aArgs, aReturnValue, "todolist_aa33_create_entry_with: "_ns, aError);
return true;
}
case 107: { // custom_types:custom_types_8ecd_get_custom_types_demo
case 107: { // fixture_callbacks:fixture_callbacks_1107_log_even_numbers
using CallHandler = ScaffoldingCallHandler<ScaffoldingConverter<void>, ScaffoldingConverter<uint64_t>, ScaffoldingConverter<RustBuffer>>;
CallHandler::CallSync(fixture_callbacks_1107_log_even_numbers, aGlobal, aArgs, aReturnValue, "fixture_callbacks_1107_log_even_numbers: "_ns, aError);
return true;
}
case 108: { // fixture_callbacks:fixture_callbacks_1107_log_even_numbers_main_thread
using CallHandler = ScaffoldingCallHandler<ScaffoldingConverter<void>, ScaffoldingConverter<uint64_t>, ScaffoldingConverter<RustBuffer>>;
CallHandler::CallSync(fixture_callbacks_1107_log_even_numbers_main_thread, aGlobal, aArgs, aReturnValue, "fixture_callbacks_1107_log_even_numbers_main_thread: "_ns, aError);
return true;
}
case 109: { // custom_types:custom_types_8ecd_get_custom_types_demo
using CallHandler = ScaffoldingCallHandler<ScaffoldingConverter<RustBuffer>, ScaffoldingConverter<RustBuffer>>;
CallHandler::CallSync(custom_types_8ecd_get_custom_types_demo, aGlobal, aArgs, aReturnValue, "custom_types_8ecd_get_custom_types_demo: "_ns, aError);
return true;
}
case 108: { // external_types:external_types_54cc_gradient
case 110: { // external_types:external_types_54cc_gradient
using CallHandler = ScaffoldingCallHandler<ScaffoldingConverter<double>, ScaffoldingConverter<RustBuffer>>;
CallHandler::CallSync(external_types_54cc_gradient, aGlobal, aArgs, aReturnValue, "external_types_54cc_gradient: "_ns, aError);
return true;

Просмотреть файл

@ -2,18 +2,23 @@
#include "nsString.h"
#include "nsPrintfCString.h"
#include "mozilla/Logging.h"
#include "mozilla/Maybe.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/dom/UniFFICallbacks.h"
#include "mozilla/dom/UniFFIScaffolding.h"
#include "mozilla/dom/ScaffoldingCall.h"
namespace mozilla::uniffi {
using dom::ArrayBuffer;
using dom::AutoEntryScript;
using dom::GlobalObject;
using dom::RootedDictionary;
using dom::Promise;
using dom::ScaffoldingType;
using dom::Sequence;
using dom::UniFFICallbackHandler;
using dom::UniFFIPointer;
using dom::UniFFIScaffoldingCallResult;
@ -53,6 +58,17 @@ const static mozilla::uniffi::UniFFIPointerType kTabsTabsBridgedEnginePointerTyp
ffi_tabs_edc9_TabsBridgedEngine_object_free
};
// Define the data we need per-callback interface
// Define a lookup function for our callback interface info
Maybe<CallbackInterfaceInfo> UniFFIGetCallbackInterfaceInfo(uint64_t aInterfaceId) {
switch(aInterfaceId) {
default:
return Nothing();
}
}
Maybe<already_AddRefed<Promise>> UniFFICallAsync(const GlobalObject& aGlobal, uint64_t aId, const Sequence<ScaffoldingType>& aArgs, ErrorResult& aError) {
switch (aId) {
case 0: { // tabs:tabs_edc9_TabsStore_new

Просмотреть файл

@ -18,6 +18,13 @@ constexpr int8_t RUST_CALL_SUCCESS = 0;
constexpr int8_t RUST_CALL_ERROR = 1;
constexpr int8_t RUST_CALL_INTERNAL_ERROR = 2;
// Return values for callback interfaces (See
// https://github.com/mozilla/uniffi-rs/blob/main/uniffi/src/ffi/foreigncallbacks.rs
// for details)
constexpr int8_t CALLBACK_INTERFACE_SUCCESS = 1;
constexpr int8_t CALLBACK_INTERFACE_INTERNAL_ERROR = -1;
constexpr int8_t CALLBACK_INTERFACE_ERROR = -2;
// structs/functions from UniFFI
extern "C" {
struct RustBuffer {
@ -31,6 +38,9 @@ struct RustCallStatus {
RustBuffer error_buf;
};
typedef int (*ForeignCallback)(uint64_t handle, uint32_t method,
RustBuffer args, RustBuffer* buf_ptr);
RustBuffer uniffi_rustbuffer_alloc(int32_t size, RustCallStatus* call_status);
void uniffi_rustbuffer_free(RustBuffer buf, RustCallStatus* call_status);
}

Просмотреть файл

@ -10,6 +10,7 @@
#include "nsPrintfCString.h"
#include "mozilla/Maybe.h"
#include "mozilla/dom/UniFFIScaffolding.h"
#include "mozilla/dom/UniFFICallbacks.h"
// This file implements the UniFFI WebIDL interface by leveraging the generate
// code in UniFFIScaffolding.cpp and UniFFIFixtureScaffolding.cpp. It's main
@ -22,6 +23,7 @@ using mozilla::dom::Promise;
using mozilla::dom::RootedDictionary;
using mozilla::dom::ScaffoldingType;
using mozilla::dom::Sequence;
using mozilla::dom::UniFFICallbackHandler;
using mozilla::dom::UniFFIPointer;
using mozilla::dom::UniFFIScaffoldingCallResult;
@ -145,4 +147,16 @@ void UniFFIScaffolding::WritePointer(const GlobalObject& aGlobal, uint64_t aId,
aError.ThrowUnknownError(nsPrintfCString("Unknown object id: %" PRIu64, aId));
}
void UniFFIScaffolding::RegisterCallbackHandler(
GlobalObject& aGlobal, uint64_t aInterfaceId,
UniFFICallbackHandler& aCallbackHandler, ErrorResult& aError) {
uniffi::RegisterCallbackHandler(aInterfaceId, aCallbackHandler, aError);
}
void UniFFIScaffolding::DeregisterCallbackHandler(GlobalObject& aGlobal,
uint64_t aInterfaceId,
ErrorResult& aError) {
uniffi::DeregisterCallbackHandler(aInterfaceId, aError);
}
} // namespace mozilla::dom

Просмотреть файл

@ -20,23 +20,31 @@ using ScaffoldingType = OwningDoubleOrArrayBufferOrUniFFIPointer;
class UniFFIScaffolding {
public:
static already_AddRefed<Promise> CallAsync(
const GlobalObject& aUniFFIGlobal, uint64_t aId,
const Sequence<ScaffoldingType>& aArgs, ErrorResult& aUniFFIErrorResult);
const GlobalObject& aGlobal, uint64_t aId,
const Sequence<ScaffoldingType>& aArgs, ErrorResult& aErrorResult);
static void CallSync(
const GlobalObject& aUniFFIGlobal, uint64_t aId,
const GlobalObject& aGlobal, uint64_t aId,
const Sequence<ScaffoldingType>& aArgs,
RootedDictionary<UniFFIScaffoldingCallResult>& aUniFFIReturnValue,
ErrorResult& aUniFFIErrorResult);
RootedDictionary<UniFFIScaffoldingCallResult>& aReturnValue,
ErrorResult& aErrorResult);
static already_AddRefed<UniFFIPointer> ReadPointer(
const GlobalObject& aUniFFIGlobal, uint64_t aId,
const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError);
const GlobalObject& aGlobal, uint64_t aId, const ArrayBuffer& aArrayBuff,
long aPosition, ErrorResult& aError);
static void WritePointer(const GlobalObject& aUniFFIGlobal, uint64_t aId,
static void WritePointer(const GlobalObject& aGlobal, uint64_t aId,
const UniFFIPointer& aPtr,
const ArrayBuffer& aArrayBuff, long aPosition,
ErrorResult& aError);
static void RegisterCallbackHandler(GlobalObject& aGlobal,
uint64_t interfaceId,
UniFFICallbackHandler& aCallbackHandler,
ErrorResult& aError);
static void DeregisterCallbackHandler(GlobalObject& aGlobal,
uint64_t interfaceId,
ErrorResult& aError);
};
} // namespace mozilla::dom

Просмотреть файл

@ -8,6 +8,7 @@ FINAL_LIBRARY = "xul"
UNIFIED_SOURCES += [
"OwnedRustBuffer.cpp",
"UniFFICallbacks.cpp",
"UniFFIGeneratedScaffolding.cpp",
"UniFFIPointer.cpp",
"UniFFIScaffolding.cpp",
@ -23,6 +24,7 @@ EXPORTS.mozilla.dom += [
"OwnedRustBuffer.h",
"ScaffoldingCall.h",
"ScaffoldingConverter.h",
"UniFFICallbacks.h",
"UniFFIPointer.h",
"UniFFIPointerType.h",
"UniFFIRust.h",

Просмотреть файл

@ -75,12 +75,13 @@ origin-trials-ffi = { path = "../../../../dom/origin-trials/ffi" }
jog = { path = "../../../components/glean/bindings/jog" }
dap_ffi = { path = "../../../components/telemetry/dap/ffi" }
data-encoding-ffi = { path = "../../../../dom/fs/parent/rust/data-encoding-ffi" }
uniffi-example-arithmetic = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "bb2039f077a29dba0879372a67e764e6ace8e33f", optional = true }
uniffi-example-geometry = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "bb2039f077a29dba0879372a67e764e6ace8e33f", optional = true }
uniffi-example-rondpoint = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "bb2039f077a29dba0879372a67e764e6ace8e33f", optional = true }
uniffi-example-sprites = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "bb2039f077a29dba0879372a67e764e6ace8e33f", optional = true }
uniffi-example-todolist = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "bb2039f077a29dba0879372a67e764e6ace8e33f", optional = true }
uniffi-example-arithmetic = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "846612a1d4fb5d11e246bf0682da4a499409424c", optional = true }
uniffi-example-geometry = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "846612a1d4fb5d11e246bf0682da4a499409424c", optional = true }
uniffi-example-rondpoint = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "846612a1d4fb5d11e246bf0682da4a499409424c", optional = true }
uniffi-example-sprites = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "846612a1d4fb5d11e246bf0682da4a499409424c", optional = true }
uniffi-example-todolist = { git = "https://github.com/mozilla/uniffi-rs.git", rev = "846612a1d4fb5d11e246bf0682da4a499409424c", optional = true }
uniffi-example-custom-types = { path = "../../../components/uniffi-example-custom-types/", optional = true }
uniffi-fixture-callbacks = { path = "../../../components/uniffi-fixture-callbacks/", optional = true }
uniffi-fixture-external-types = { path = "../../../components/uniffi-fixture-external-types/", optional = true }
binary_http = { path = "../../../../netwerk/protocol/http/binary_http" }
oblivious_http = { path = "../../../../netwerk/protocol/http/oblivious_http" }
@ -146,7 +147,8 @@ with_dbus = ["audio_thread_priority/with_dbus"]
thread_sanitizer = ["xpcom/thread_sanitizer"]
uniffi_fixtures = [
"uniffi-example-arithmetic", "uniffi-example-geometry", "uniffi-example-rondpoint", "uniffi-example-sprites",
"uniffi-example-todolist", "uniffi-example-custom-types", "uniffi-fixture-external-types",
"uniffi-example-todolist", "uniffi-example-custom-types", "uniffi-fixture-callbacks",
"uniffi-fixture-external-types",
]
webmidi_midir_impl = ["midir_impl"]

Просмотреть файл

@ -70,9 +70,9 @@ extern crate mdns_service;
extern crate neqo_glue;
extern crate wgpu_bindings;
extern crate aa_stroke;
extern crate qcms;
extern crate wpf_gpu_raster;
extern crate aa_stroke;
extern crate unic_langid;
extern crate unic_langid_ffi;
@ -121,6 +121,7 @@ mod uniffi_fixtures {
extern crate uniffi_todolist;
arithmetical::uniffi_reexport_scaffolding!();
uniffi_fixture_callbacks::uniffi_reexport_scaffolding!();
uniffi_custom_types::uniffi_reexport_scaffolding!();
uniffi_fixture_external_types::uniffi_reexport_scaffolding!();
uniffi_geometry::uniffi_reexport_scaffolding!();