Backed out 2 changesets (bug 1766045) for causing Bp-hybrid failures on UniFFIGeneratedScaffolding.cpp

Backed out changeset 5708672d0e83 (bug 1766045)
Backed out changeset cc77fd5ec7a8 (bug 1766045)
This commit is contained in:
criss 2022-08-03 00:01:58 +03:00
Родитель c4289c274d
Коммит 04616ca52e
144 изменённых файлов: 0 добавлений и 7761 удалений

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

@ -12,11 +12,6 @@ git = "https://github.com/rust-minidump/minidump-writer.git"
replace-with = "vendored-sources"
rev = "75ada456c92a429704691a85e1cb42fef8cafc0d"
[source."https://github.com/mozilla/uniffi-rs.git"]
git = "https://github.com/mozilla/uniffi-rs.git"
replace-with = "vendored-sources"
rev = "bb2039f077a29dba0879372a67e764e6ace8e33f"
[source."https://github.com/mozilla/neqo"]
git = "https://github.com/mozilla/neqo"
replace-with = "vendored-sources"

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

@ -63,12 +63,6 @@ widget/gtk/MPRISInterfaceDescription.h
xpcom/reflect/xptcall/md/win32/.*
xpcom/reflect/xptcall/md/unix/.*
# Askama template code, which isn't valid C++ in its original form
toolkit/components/uniffi-bindgen-gecko-js/src/templates/.*
# Generated from that template code
toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp
toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp
# Generated from ./tools/rewriting/ThirdPartyPaths.txt
# awk '{print ""$1".*"}' ./tools/rewriting/ThirdPartyPaths.txt
browser/components/translation/cld2/.*

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

@ -228,6 +228,3 @@ toolkit/components/backgroundtasks/defaults
# Ignore pre-generated webpack and typescript transpiled files for translations
browser/extensions/translations/extension/
# "scaffolding" used by uniffi which isn't valid JS in its original form.
toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/

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

@ -1549,18 +1549,6 @@ dependencies = [
"serde",
]
[[package]]
name = "extend"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5216e387a76eebaaf11f6d871ec8a4aae0b25f05456ee21f228e024b1b3610"
dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "fallible-iterator"
version = "0.2.0"
@ -2176,11 +2164,6 @@ dependencies = [
"tokio-threadpool",
"unic-langid",
"unic-langid-ffi",
"uniffi-example-arithmetic",
"uniffi-example-geometry",
"uniffi-example-rondpoint",
"uniffi-example-sprites",
"uniffi-example-todolist",
"url",
"viaduct",
"webext_storage_bridge",
@ -5619,75 +5602,6 @@ dependencies = [
"log",
"paste",
"static_assertions",
"uniffi_bindgen",
]
[[package]]
name = "uniffi-bindgen-gecko-js"
version = "0.1.0"
dependencies = [
"anyhow",
"askama",
"camino",
"clap",
"extend",
"heck",
"serde",
"toml 0.5.9",
"uniffi_bindgen",
]
[[package]]
name = "uniffi-example-arithmetic"
version = "0.18.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=bb2039f077a29dba0879372a67e764e6ace8e33f#bb2039f077a29dba0879372a67e764e6ace8e33f"
dependencies = [
"thiserror",
"uniffi",
"uniffi_build",
"uniffi_macros",
]
[[package]]
name = "uniffi-example-geometry"
version = "0.18.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=bb2039f077a29dba0879372a67e764e6ace8e33f#bb2039f077a29dba0879372a67e764e6ace8e33f"
dependencies = [
"uniffi",
"uniffi_build",
"uniffi_macros",
]
[[package]]
name = "uniffi-example-rondpoint"
version = "0.18.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=bb2039f077a29dba0879372a67e764e6ace8e33f#bb2039f077a29dba0879372a67e764e6ace8e33f"
dependencies = [
"uniffi",
"uniffi_build",
"uniffi_macros",
]
[[package]]
name = "uniffi-example-sprites"
version = "0.18.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=bb2039f077a29dba0879372a67e764e6ace8e33f#bb2039f077a29dba0879372a67e764e6ace8e33f"
dependencies = [
"uniffi",
"uniffi_build",
"uniffi_macros",
]
[[package]]
name = "uniffi-example-todolist"
version = "0.18.0"
source = "git+https://github.com/mozilla/uniffi-rs.git?rev=bb2039f077a29dba0879372a67e764e6ace8e33f#bb2039f077a29dba0879372a67e764e6ace8e33f"
dependencies = [
"lazy_static",
"thiserror",
"uniffi",
"uniffi_build",
"uniffi_macros",
]
[[package]]

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

@ -11,7 +11,6 @@ members = [
"security/manager/ssl/ipcclientcerts",
"security/manager/ssl/osclientcerts",
"testing/geckodriver",
"toolkit/components/uniffi-bindgen-gecko-js",
"toolkit/crashreporter/rust_minidump_writer_linux",
"toolkit/crashreporter/mozwer-rust",
"toolkit/library/gtest/rust",
@ -165,16 +164,3 @@ path = "third_party/rust/mio-0.6.23"
# https://github.com/mozilla/neqo/pull/1350
[patch."https://github.com/mozilla/neqo"]
neqo-common = { path = "third_party/rust/neqo-common" }
# These are used to test UniFFI functionality. We haven't figured out how we
# want to publish these yet, so they are only accessible via git. This works
# okay, but it means that their dependencies on UniFFI crates will normally
# also be the git versions. Patch them to use the published versions to avoid
# duplicate crates.
[patch."https://github.com/mozilla/uniffi-rs.git"]
uniffi = "0.19"
uniffi_bindgen = "0.19"
uniffi_build = "0.19"
uniffi_macros = "0.19"
weedle2 = "3.0.0"

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

@ -1,59 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Interface for making UniFFI scaffolding calls
//
// Gecko uses UniFFI to generate privileged JS bindings for Rust components.
// UniFFI defines a C-ABI FFI layer for calling into Rust, called the
// scaffolding. This interface is a bridge that allows the JS code to make
// scaffolding calls
//
// See https://mozilla.github.io/uniffi-rs/ for details.
// Opaque type used to represent a pointer from Rust
[ChromeOnly, Exposed=Window]
interface UniFFIPointer {};
// Types that can be passed or returned from scaffolding functions
//
// - double is used for all numeric types (including bool, which the JS code
// coerces to an int)
// - ArrayBuffer is used for RustBuffer
// - UniFFIPointer is used for Arc pointers
typedef (double or ArrayBuffer or UniFFIPointer) UniFFIScaffoldingType;
// The result of a call into UniFFI scaffolding call
enum UniFFIScaffoldingCallCode {
"success", // Successful return
"error", // Rust Err return
"internal-error", // Internal/unexpected error
};
dictionary UniFFIScaffoldingCallResult {
required UniFFIScaffoldingCallCode code;
// For success, this will be the return value for non-void returns
// For error, this will be an ArrayBuffer storing the serialized error value
UniFFIScaffoldingType data;
// For internal-error, this will be a utf-8 string describing the error
ByteString internalErrorMessage;
};
// Functions to facilitate UniFFI scaffolding calls
//
// These should only be called by the generated code from UniFFI.
[ChromeOnly, Exposed=Window]
namespace UniFFIScaffolding {
[Throws]
Promise<UniFFIScaffoldingCallResult> callAsync(unsigned long long id, UniFFIScaffoldingType... args);
[Throws]
UniFFIScaffoldingCallResult callSync(unsigned long long id, UniFFIScaffoldingType... args);
[Throws]
UniFFIPointer readPointer(unsigned long long id, ArrayBuffer buff, long position);
[Throws]
void writePointer(unsigned long long id, UniFFIPointer ptr, ArrayBuffer buff, long position);
};

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

@ -81,7 +81,6 @@ WEBIDL_FILES = [
"SessionStoreUtils.webidl",
"StructuredCloneHolder.webidl",
"TelemetryStopwatch.webidl",
"UniFFI.webidl",
"UserInteraction.webidl",
"WebExtensionContentScript.webidl",
"WebExtensionPolicy.webidl",

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

@ -99,12 +99,6 @@ criteria = "safe-to-deploy"
delta = "0.4.0 -> 0.5.0"
notes = "The repository for this crate belongs in the Mozilla org."
[[audits.extend]]
who = "Ben Dean-Kawamura <bdk@mozilla.com>"
criteria = "safe-to-deploy"
version = "1.1.2"
notes = "Inspected the crate and noted that the impl block comes directly from the proc-macro input. If no new code can be added by this crate, I don't think there can be any issues."
[[audits.flagset]]
who = "Ryan Hunt <rhunt@eqrion.net>"
criteria = "safe-to-deploy"

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

@ -1 +0,0 @@
{"files":{"CHANGELOG.md":"910cd2057d356b18cd4f21791bc23956734a83b0f58701ec0d0d03405f5c21df","Cargo.toml":"928b8b97607b3589b85a6d4d00fb1cf64b78bee6354c303d8f49fbfa2ca5bdae","LICENSE":"db0efd0bb80126f32214f478434536d07d86a30658fb209d8b543b7261492a2b","README.md":"0872b2b15ec22732a09b121a31cdd8f8cfc80566f671566e4a7fb6b52a742a2e","deny.toml":"60448e9313f1883a7adf30713fcca789c454e77228105926024ce3abe9293100","rustfmt.toml":"9bbb759b3914c49c8060bcdeeb7786f4aec083d30bcfe236bbd48d8388d06103","src/lib.rs":"85bd23c064c78dcd141cb2fecca6fff2ee7e1dfb4cf19b74ab97ef30d51f6f03","tests/compile_fail/double_vis.rs":"524e8bc996f5a45de3d15f0c741d4f3414004e9c636c52de0f011785cc535109","tests/compile_fail/double_vis.stderr":"3748e67e6f41bd5624946ad7cdc4e2b30a9d0b5e76bc27c19ecc9d62da733978","tests/compile_fail/supertraits_are_actually_included.rs":"c03980316c4e71ceb7e80ab7011f00b6f1f8f89906670e9823267a4118f72853","tests/compile_fail/supertraits_are_actually_included.stderr":"835e79bb1bceb48e9db5f0a410c57af51c856e17917ef72f65e3ae2af79d97ec","tests/compile_pass/associated_constants.rs":"f3e56405650ddd31c33e932846553e88fe7181585e0f09a7414d50d521b0f103","tests/compile_pass/async_trait.rs":"9138801d67dbe20ed87fdb3f48bb968f0bfa11fe2d27414d5ea5ea7a6e44bb35","tests/compile_pass/changing_extension_trait_name.rs":"046e7a66151ce05c3515b4bea36be72f83b98f3bdb06fa6f065ad6fc373e19f2","tests/compile_pass/complex_trait_name.rs":"5a8c3588c26df07973739fbb85619d0de480cc8c992611dfc2dbcb9ab3c6e2b6","tests/compile_pass/double_ext_on_same_type.rs":"0e4d16fe9059f0325e4ad1337d53738876633b0533f9a2d4e9714ddada96eb4d","tests/compile_pass/extension_on_complex_types.rs":"88bdf979e1f399d7f9824165730b33884bc9c46347d246f8cc12e0e2039642a1","tests/compile_pass/generics.rs":"367f089e8010d1c98ccc975b03acb6cf03810793e1198105f75c006eafd52bb8","tests/compile_pass/hello_world.rs":"1961cfa634143974f0d64b26f817ac3148375faa5cf5864d63f0127d3af8099e","tests/compile_pass/issue_2.rs":"a14d5e2179b74ff71c5357e8a4f1a9ac228a711196edd40c12719565c8dfaa21","tests/compile_pass/more_than_one_extension.rs":"1d7486e4e9e4095d7e7f42aac878d836f021c49fbe26c31cb13fe6a0415a8558","tests/compile_pass/multiple_config.rs":"dc3b06e4fafbb7236b5bc49f9a5e9693241c07118da8886dd0752b895ff27425","tests/compile_pass/multiple_generic_params.rs":"2ac052ea7b818b6d45ee8070cf6ec18953419473f711375cafbe7283244b5743","tests/compile_pass/pub_impl.rs":"8dfcba21fbbc45efcf85b66fca2d187022569e72d4b10b57047eddda67a1725b","tests/compile_pass/ref_and_ref_mut.rs":"d1086a23809cbd8f87487677073238c3657a8a98fafc63a688eb9d622bf2eb11","tests/compile_pass/sized.rs":"baceaaabcf368b3c72e6d27fea72aadde11d97d9d153c35df5e2d89fb3da4e3e","tests/compile_pass/super_trait.rs":"07448e1fe2b9018125ccaabf7db1e2a244788519bb42117f8e437e48358eb2f0","tests/compile_pass/visibility_config.rs":"64846014a63327661fb250cdb726cce532ed82b1cea5cb83308526bcba22b4be"},"package":"5c5216e387a76eebaaf11f6d871ec8a4aae0b25f05456ee21f228e024b1b3610"}

79
third_party/rust/extend/CHANGELOG.md поставляемый
Просмотреть файл

@ -1,79 +0,0 @@
# Change Log
All user visible changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/), as described
for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/text/1105-api-evolution.md)
## Unreleased
None.
### Breaking changes
None.
## 1.1.2 - 2021-09-02
- Fix using `pub impl` with `#[async_trait]`.
## 1.1.1 - 2021-06-12
- Fix name collision for extensions on `&T` and `&mut T`. The generated traits
now get different names.
## 1.1.0 - 2021-06-12
- Support setting visibility of the generated trait directly on the `impl`
block. For example: `pub impl i32 { ... }`.
- Add `#[ext_sized]` for adding `Sized` supertrait.
## 1.0.1 - 2021-02-14
- Update maintenance status.
## 1.0.0 - 2021-01-30
- Support extensions on bare functions types (things like `fn(i32) -> bool`).
- Support extensions on trait objects (things like `dyn Send + Sync`).
## 0.3.0 - 2020-08-31
- Add async-trait compatibility.
### Breaking changes
- Other attributes put on the `impl` would previously only be included on the generated trait. They're now included on both the trait and the implementation.
## 0.2.1 - 2020-08-29
- Fix documentation link in Cargo.toml.
- Use more correct repository URL in Cargo.toml.
## 0.2.0 - 2020-08-29
- Handle unnamed extensions on the same generic type with different type parameters. For example `Option<i32>` and `Option<String>`. Previously we would generate the same name of both hidden traits which wouldn't compile.
- Support associated constants in extension impls.
### Breaking changes
- Generated traits are no longer sealed and the `sealed` argument previously supported by `#[ext]` has been removed. Making the traits sealed lead to lots of complexity that we didn't think brought much value.
## 0.1.1 - 2020-02-22
- Add support for specifying supertraits of the generated trait [#4](https://github.com/davidpdrsn/extend/pull/4).
## 0.1.0
- Support adding extensions to the ["never type"](https://doc.rust-lang.org/std/primitive.never.html).
### Breaking changes
- Simplify names of traits generates for complex types.
## 0.0.2
- Move "trybuild" to dev-dependency.
## 0.0.1
Initial release.

48
third_party/rust/extend/Cargo.toml поставляемый
Просмотреть файл

@ -1,48 +0,0 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
edition = "2018"
name = "extend"
version = "1.1.2"
authors = ["David Pedersen <david.pdrsn@gmail.com>"]
description = "Create extensions for types you don't own with extension traits but without the boilerplate."
homepage = "https://github.com/davidpdrsn/extend"
documentation = "https://docs.rs/extend"
readme = "README.md"
keywords = ["extension", "trait"]
categories = ["rust-patterns"]
license = "MIT"
repository = "https://github.com/davidpdrsn/extend.git"
[lib]
path = "src/lib.rs"
proc-macro = true
[dependencies.proc-macro-error]
version = "1"
[dependencies.proc-macro2]
version = "1"
[dependencies.quote]
version = "1"
[dependencies.syn]
version = "1"
features = ["full", "extra-traits", "visit"]
[dev-dependencies.async-trait]
version = "0.1.40"
[dev-dependencies.trybuild]
version = "1.0.17"
[badges.maintenance]
status = "passively-maintained"

19
third_party/rust/extend/LICENSE поставляемый
Просмотреть файл

@ -1,19 +0,0 @@
MIT License Copyright (c) 2020 David Pedersen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

32
third_party/rust/extend/README.md поставляемый
Просмотреть файл

@ -1,32 +0,0 @@
# extend
[![Crates.io](https://img.shields.io/crates/v/extend.svg)](https://crates.io/crates/extend)
[![Docs](https://docs.rs/extend/badge.svg)](https://docs.rs/extend)
[![dependency status](https://deps.rs/repo/github/davidpdrsn/extend/status.svg)](https://deps.rs/repo/github/davidpdrsn/extend)
[![Build status](https://github.com/davidpdrsn/extend/workflows/CI/badge.svg)](https://github.com/davidpdrsn/extend/actions)
![maintenance-status](https://img.shields.io/badge/maintenance-passively--maintained-yellowgreen.svg)
Create extensions for types you don't own with [extension traits] but without the boilerplate.
Example:
```rust
use extend::ext;
#[ext]
impl<T: Ord> Vec<T> {
fn sorted(mut self) -> Self {
self.sort();
self
}
}
fn main() {
assert_eq!(
vec![1, 2, 3],
vec![2, 3, 1].sorted(),
);
}
```
[extension traits]: https://dev.to/matsimitsu/extending-existing-functionality-in-rust-with-traits-in-rust-3622

47
third_party/rust/extend/deny.toml поставляемый
Просмотреть файл

@ -1,47 +0,0 @@
targets = []
[advisories]
db-path = "~/.cargo/advisory-db"
db-urls = ["https://github.com/rustsec/advisory-db"]
vulnerability = "deny"
unmaintained = "warn"
yanked = "warn"
notice = "warn"
ignore = []
[licenses]
unlicensed = "deny"
allow = [
"MIT",
"Apache-2.0",
]
deny = []
copyleft = "warn"
allow-osi-fsf-free = "neither"
default = "deny"
confidence-threshold = 0.8
exceptions = []
[licenses.private]
ignore = false
registries = []
[bans]
multiple-versions = "deny"
wildcards = "allow"
highlight = "all"
allow = []
deny = []
skip = []
skip-tree = []
[sources]
unknown-registry = "warn"
unknown-git = "warn"
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
allow-git = []
[sources.allow-org]
github = []
gitlab = []
bitbucket = []

1
third_party/rust/extend/rustfmt.toml поставляемый
Просмотреть файл

@ -1 +0,0 @@
merge_imports = true

620
third_party/rust/extend/src/lib.rs поставляемый
Просмотреть файл

@ -1,620 +0,0 @@
//! Create extensions for types you don't own with [extension traits] but without the boilerplate.
//!
//! Example:
//!
//! ```rust
//! use extend::ext;
//!
//! #[ext]
//! impl<T: Ord> Vec<T> {
//! fn sorted(mut self) -> Self {
//! self.sort();
//! self
//! }
//! }
//!
//! fn main() {
//! assert_eq!(
//! vec![1, 2, 3],
//! vec![2, 3, 1].sorted(),
//! );
//! }
//! ```
//!
//! # How does it work?
//!
//! Under the hood it generates a trait with methods in your `impl` and implements those for the
//! type you specify. The code shown above expands roughly to:
//!
//! ```rust
//! trait VecExt<T: Ord> {
//! fn sorted(self) -> Self;
//! }
//!
//! impl<T: Ord> VecExt<T> for Vec<T> {
//! fn sorted(mut self) -> Self {
//! self.sort();
//! self
//! }
//! }
//! ```
//!
//! # Supported items
//!
//! Extensions can contain methods or associated constants:
//!
//! ```rust
//! use extend::ext;
//!
//! #[ext]
//! impl String {
//! const CONSTANT: &'static str = "FOO";
//!
//! fn method() {
//! // ...
//! # todo!()
//! }
//! }
//! ```
//!
//! # Configuration
//!
//! You can configure:
//!
//! - The visibility of the trait. Use `pub impl ...` to generate `pub trait ...`. The default
//! visibility is private.
//! - The name of the generated extension trait. Example: `#[ext(name = MyExt)]`. By default we
//! generate a name based on what you extend.
//! - Which supertraits the generated extension trait should have. Default is no supertraits.
//! Example: `#[ext(supertraits = Default + Clone)]`.
//!
//! More examples:
//!
//! ```rust
//! use extend::ext;
//!
//! #[ext(name = SortedVecExt)]
//! impl<T: Ord> Vec<T> {
//! fn sorted(mut self) -> Self {
//! self.sort();
//! self
//! }
//! }
//!
//! #[ext]
//! pub(crate) impl i32 {
//! fn double(self) -> i32 {
//! self * 2
//! }
//! }
//!
//! #[ext(name = ResultSafeUnwrapExt)]
//! pub impl<T> Result<T, std::convert::Infallible> {
//! fn safe_unwrap(self) -> T {
//! match self {
//! Ok(t) => t,
//! Err(_) => unreachable!(),
//! }
//! }
//! }
//!
//! #[ext(supertraits = Default + Clone)]
//! impl String {
//! fn my_length(self) -> usize {
//! self.len()
//! }
//! }
//! ```
//!
//! For backwards compatibility you can also declare the visibility as the first argument to `#[ext]`:
//!
//! ```
//! use extend::ext;
//!
//! #[ext(pub)]
//! impl i32 {
//! fn double(self) -> i32 {
//! self * 2
//! }
//! }
//! ```
//!
//! # async-trait compatibility
//!
//! Async extensions are supported via [async-trait](https://crates.io/crates/async-trait).
//!
//! Be aware that you need to add `#[async_trait]` _below_ `#[ext]`. Otherwise the `ext` macro
//! cannot see the `#[async_trait]` attribute and pass it along in the generated code.
//!
//! Example:
//!
//! ```
//! use extend::ext;
//! use async_trait::async_trait;
//!
//! #[ext]
//! #[async_trait]
//! impl String {
//! async fn read_file() -> String {
//! // ...
//! # todo!()
//! }
//! }
//! ```
//!
//! # Other attributes
//!
//! Other attributes provided _below_ `#[ext]` will be passed along to both the generated trait and
//! the implementation. See [async-trait compatibility](#async-trait-compatibility) above for an
//! example.
//!
//! [extension traits]: https://dev.to/matsimitsu/extending-existing-functionality-in-rust-with-traits-in-rust-3622
#![doc(html_root_url = "https://docs.rs/extend/1.1.2")]
#![allow(clippy::let_and_return)]
#![deny(
unused_variables,
mutable_borrow_reservation_conflict,
dead_code,
unused_must_use,
unused_imports
)]
use proc_macro2::TokenStream;
use proc_macro_error::*;
use quote::{format_ident, quote, ToTokens};
use syn::{
parse::{self, Parse, ParseStream},
parse_macro_input, parse_quote,
punctuated::Punctuated,
spanned::Spanned,
token::{Add, Semi},
Ident, ImplItem, ItemImpl, Token, TraitItemConst, TraitItemMethod, Type, TypeArray, TypeBareFn,
TypeGroup, TypeNever, TypeParamBound, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice,
TypeTraitObject, TypeTuple, Visibility,
};
#[derive(Debug)]
struct Input {
item_impl: ItemImpl,
vis: Option<Visibility>,
}
impl Parse for Input {
fn parse(input: ParseStream) -> syn::Result<Self> {
let mut attributes = Vec::new();
if input.peek(syn::Token![#]) {
attributes.extend(syn::Attribute::parse_outer(input)?);
}
let vis = input
.parse::<Visibility>()
.ok()
.filter(|vis| vis != &Visibility::Inherited);
let mut item_impl = input.parse::<ItemImpl>()?;
item_impl.attrs.extend(attributes);
Ok(Self { item_impl, vis })
}
}
/// See crate docs for more info.
#[proc_macro_attribute]
#[proc_macro_error]
#[allow(clippy::unneeded_field_pattern)]
pub fn ext(
attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let item = parse_macro_input!(item as Input);
let config = parse_macro_input!(attr as Config);
go(item, config)
}
/// Like [`ext`](macro@crate::ext) but always add `Sized` as a supertrait.
///
/// This is provided as a convenience for generating extension traits that require `Self: Sized`
/// such as:
///
/// ```
/// use extend::ext_sized;
///
/// #[ext_sized]
/// impl i32 {
/// fn requires_sized(self) -> Option<Self> {
/// Some(self)
/// }
/// }
/// ```
#[proc_macro_attribute]
#[proc_macro_error]
#[allow(clippy::unneeded_field_pattern)]
pub fn ext_sized(
attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let item = parse_macro_input!(item as Input);
let mut config: Config = parse_macro_input!(attr as Config);
config.supertraits = if let Some(supertraits) = config.supertraits.take() {
Some(parse_quote!(#supertraits + Sized))
} else {
Some(parse_quote!(Sized))
};
go(item, config)
}
fn go(item: Input, mut config: Config) -> proc_macro::TokenStream {
if let Some(vis) = item.vis {
if config.visibility != Visibility::Inherited {
abort!(
config.visibility.span(),
"Cannot set visibility on `#[ext]` and `impl` block"
);
}
config.visibility = vis;
}
let ItemImpl {
attrs,
unsafety,
generics,
trait_,
self_ty,
items,
// What is defaultness?
defaultness: _,
impl_token: _,
brace_token: _,
} = item.item_impl;
if let Some((_, path, _)) = trait_ {
abort!(path.span(), "Trait impls cannot be used for #[ext]");
}
let self_ty = parse_self_ty(&self_ty);
let ext_trait_name = config
.ext_trait_name
.unwrap_or_else(|| ext_trait_name(&self_ty));
let MethodsAndConsts {
trait_methods,
trait_consts,
} = extract_allowed_items(&items);
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let visibility = &config.visibility;
let mut all_supertraits = Vec::<TypeParamBound>::new();
if let Some(supertraits_from_config) = config.supertraits {
all_supertraits.extend(supertraits_from_config);
}
let supertraits_quoted = if all_supertraits.is_empty() {
quote! {}
} else {
let supertraits_quoted = punctuated_from_iter::<_, _, Add>(all_supertraits);
quote! { : #supertraits_quoted }
};
let code = (quote! {
#[allow(non_camel_case_types)]
#(#attrs)*
#visibility
#unsafety
trait #ext_trait_name #impl_generics #supertraits_quoted #where_clause {
#(
#trait_consts
)*
#(
#[allow(
patterns_in_fns_without_body,
clippy::inline_fn_without_body,
unused_attributes
)]
#trait_methods
)*
}
#(#attrs)*
impl #impl_generics #ext_trait_name #ty_generics for #self_ty #where_clause {
#(#items)*
}
})
.into();
code
}
#[derive(Debug, Clone)]
enum ExtType<'a> {
Array(&'a TypeArray),
Group(&'a TypeGroup),
Never(&'a TypeNever),
Paren(&'a TypeParen),
Path(&'a TypePath),
Ptr(&'a TypePtr),
Reference(&'a TypeReference),
Slice(&'a TypeSlice),
Tuple(&'a TypeTuple),
BareFn(&'a TypeBareFn),
TraitObject(&'a TypeTraitObject),
}
#[allow(clippy::wildcard_in_or_patterns)]
fn parse_self_ty(self_ty: &Type) -> ExtType {
match self_ty {
Type::Array(inner) => ExtType::Array(inner),
Type::Group(inner) => ExtType::Group(inner),
Type::Never(inner) => ExtType::Never(inner),
Type::Paren(inner) => ExtType::Paren(inner),
Type::Path(inner) => ExtType::Path(inner),
Type::Ptr(inner) => ExtType::Ptr(inner),
Type::Reference(inner) => ExtType::Reference(inner),
Type::Slice(inner) => ExtType::Slice(inner),
Type::Tuple(inner) => ExtType::Tuple(inner),
Type::BareFn(inner) => ExtType::BareFn(inner),
Type::TraitObject(inner) => ExtType::TraitObject(inner),
Type::ImplTrait(_) | Type::Infer(_) | Type::Macro(_) | Type::Verbatim(_) | _ => abort!(
self_ty.span(),
"#[ext] is not supported for this kind of type"
),
}
}
impl<'a> From<&'a Type> for ExtType<'a> {
fn from(inner: &'a Type) -> ExtType<'a> {
parse_self_ty(inner)
}
}
impl<'a> ToTokens for ExtType<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
ExtType::Array(inner) => inner.to_tokens(tokens),
ExtType::Group(inner) => inner.to_tokens(tokens),
ExtType::Never(inner) => inner.to_tokens(tokens),
ExtType::Paren(inner) => inner.to_tokens(tokens),
ExtType::Path(inner) => inner.to_tokens(tokens),
ExtType::Ptr(inner) => inner.to_tokens(tokens),
ExtType::Reference(inner) => inner.to_tokens(tokens),
ExtType::Slice(inner) => inner.to_tokens(tokens),
ExtType::Tuple(inner) => inner.to_tokens(tokens),
ExtType::BareFn(inner) => inner.to_tokens(tokens),
ExtType::TraitObject(inner) => inner.to_tokens(tokens),
}
}
}
fn ext_trait_name(self_ty: &ExtType) -> Ident {
fn inner_self_ty(self_ty: &ExtType) -> Ident {
match self_ty {
ExtType::Path(inner) => find_and_combine_idents(inner),
ExtType::Reference(inner) => {
let name = inner_self_ty(&(&*inner.elem).into());
if inner.mutability.is_some() {
format_ident!("RefMut{}", name)
} else {
format_ident!("Ref{}", name)
}
}
ExtType::Array(inner) => {
let name = inner_self_ty(&(&*inner.elem).into());
format_ident!("ListOf{}", name)
}
ExtType::Group(inner) => {
let name = inner_self_ty(&(&*inner.elem).into());
format_ident!("Group{}", name)
}
ExtType::Paren(inner) => {
let name = inner_self_ty(&(&*inner.elem).into());
format_ident!("Paren{}", name)
}
ExtType::Ptr(inner) => {
let name = inner_self_ty(&(&*inner.elem).into());
format_ident!("PointerTo{}", name)
}
ExtType::Slice(inner) => {
let name = inner_self_ty(&(&*inner.elem).into());
format_ident!("SliceOf{}", name)
}
ExtType::Tuple(inner) => {
let mut name = format_ident!("TupleOf");
for elem in &inner.elems {
name = format_ident!("{}{}", name, inner_self_ty(&elem.into()));
}
name
}
ExtType::Never(_) => format_ident!("Never"),
ExtType::BareFn(inner) => {
let mut name = format_ident!("BareFn");
for input in inner.inputs.iter() {
name = format_ident!("{}{}", name, inner_self_ty(&(&input.ty).into()));
}
match &inner.output {
syn::ReturnType::Default => {
name = format_ident!("{}Unit", name);
}
syn::ReturnType::Type(_, ty) => {
name = format_ident!("{}{}", name, inner_self_ty(&(&**ty).into()));
}
}
name
}
ExtType::TraitObject(inner) => {
let mut name = format_ident!("TraitObject");
for bound in inner.bounds.iter() {
match bound {
TypeParamBound::Trait(bound) => {
for segment in bound.path.segments.iter() {
name = format_ident!("{}{}", name, segment.ident);
}
}
TypeParamBound::Lifetime(lifetime) => {
name = format_ident!("{}{}", name, lifetime.ident);
}
}
}
name
}
}
}
format_ident!("{}Ext", inner_self_ty(self_ty))
}
fn find_and_combine_idents(type_path: &TypePath) -> Ident {
use syn::visit::{self, Visit};
struct IdentVisitor<'a>(Vec<&'a Ident>);
impl<'a> Visit<'a> for IdentVisitor<'a> {
fn visit_ident(&mut self, i: &'a Ident) {
self.0.push(i);
}
}
let mut visitor = IdentVisitor(Vec::new());
visit::visit_type_path(&mut visitor, type_path);
let idents = visitor.0;
if idents.is_empty() {
abort!(type_path.span(), "Empty type path")
} else {
let start = &idents[0].span();
let combined_span = idents
.iter()
.map(|i| i.span())
.fold(*start, |a, b| a.join(b).unwrap_or(a));
let combined_name = idents.iter().map(|i| i.to_string()).collect::<String>();
Ident::new(&combined_name, combined_span)
}
}
#[derive(Debug, Default)]
struct MethodsAndConsts {
trait_methods: Vec<TraitItemMethod>,
trait_consts: Vec<TraitItemConst>,
}
#[allow(clippy::wildcard_in_or_patterns)]
fn extract_allowed_items(items: &[ImplItem]) -> MethodsAndConsts {
let mut acc = MethodsAndConsts::default();
for item in items {
match item {
ImplItem::Method(method) => acc.trait_methods.push(TraitItemMethod {
attrs: method.attrs.clone(),
sig: method.sig.clone(),
default: None,
semi_token: Some(Semi::default()),
}),
ImplItem::Const(const_) => acc.trait_consts.push(TraitItemConst {
attrs: const_.attrs.clone(),
const_token: Default::default(),
ident: const_.ident.clone(),
colon_token: Default::default(),
ty: const_.ty.clone(),
default: None,
semi_token: Default::default(),
}),
ImplItem::Type(_) => abort!(
item.span(),
"Associated types are not allowed in #[ext] impls"
),
ImplItem::Macro(_) => abort!(item.span(), "Macros are not allowed in #[ext] impls"),
ImplItem::Verbatim(_) | _ => abort!(item.span(), "Not allowed in #[ext] impls"),
}
}
acc
}
#[derive(Debug)]
struct Config {
ext_trait_name: Option<Ident>,
visibility: Visibility,
supertraits: Option<Punctuated<TypeParamBound, Add>>,
}
impl Parse for Config {
fn parse(input: ParseStream) -> parse::Result<Self> {
let mut config = Config::default();
if let Ok(visibility) = input.parse::<Visibility>() {
config.visibility = visibility;
}
input.parse::<Token![,]>().ok();
while !input.is_empty() {
let ident = input.parse::<Ident>()?;
input.parse::<Token![=]>()?;
match &*ident.to_string() {
"name" => {
config.ext_trait_name = Some(input.parse()?);
}
"supertraits" => {
config.supertraits =
Some(Punctuated::<TypeParamBound, Add>::parse_terminated(input)?);
}
_ => abort!(ident.span(), "Unknown configuration name"),
}
input.parse::<Token![,]>().ok();
}
Ok(config)
}
}
impl Default for Config {
fn default() -> Self {
Self {
ext_trait_name: None,
visibility: Visibility::Inherited,
supertraits: None,
}
}
}
fn punctuated_from_iter<I, T, P>(i: I) -> Punctuated<T, P>
where
P: Default,
I: IntoIterator<Item = T>,
{
let mut iter = i.into_iter().peekable();
let mut acc = Punctuated::default();
while let Some(item) = iter.next() {
acc.push_value(item);
if iter.peek().is_some() {
acc.push_punct(P::default());
}
}
acc
}
#[cfg(test)]
mod test {
#[allow(unused_imports)]
use super::*;
#[test]
fn test_ui() {
let t = trybuild::TestCases::new();
t.pass("tests/compile_pass/*.rs");
t.compile_fail("tests/compile_fail/*.rs");
}
}

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

@ -1,14 +0,0 @@
mod a {
use extend::ext;
#[ext(pub(super))]
pub impl i32 {
fn foo() -> Foo {
Foo
}
}
pub struct Foo;
}
fn main() {}

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

@ -1,5 +0,0 @@
error: Cannot set visibility on `#[ext]` and `impl` block
--> $DIR/double_vis.rs:4:11
|
4 | #[ext(pub(super))]
| ^^^

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

@ -1,14 +0,0 @@
use extend::ext;
trait MyTrait {}
#[ext(supertraits = MyTrait)]
impl String {
fn my_len(&self) -> usize {
self.len()
}
}
fn main() {
assert_eq!(String::new().my_len(), 0);
}

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

@ -1,10 +0,0 @@
error[E0277]: the trait bound `String: MyTrait` is not satisfied
--> $DIR/supertraits_are_actually_included.rs:6:6
|
5 | #[ext(supertraits = MyTrait)]
| ------- required by this bound in `StringExt`
6 | impl String {
| ^^^^^^
| |
| the trait `MyTrait` is not implemented for `String`
| required by a bound in this

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

@ -1,10 +0,0 @@
use extend::ext;
#[ext]
impl Option<String> {
const FOO: usize = 1;
}
fn main() {
assert_eq!(Option::<String>::FOO, 1);
}

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

@ -1,25 +0,0 @@
use extend::ext;
use async_trait::async_trait;
#[ext]
#[async_trait]
impl String {
async fn foo() -> usize {
1
}
}
#[ext]
#[async_trait]
pub impl i32 {
async fn bar() -> usize {
1
}
}
async fn foo() {
let _: usize = String::foo().await;
let _: usize = i32::bar().await;
}
fn main() {}

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

@ -1,10 +0,0 @@
use extend::ext;
#[ext(name = Foo)]
impl i32 {
fn foo() {}
}
fn main() {
<i32 as Foo>::foo();
}

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

@ -1,16 +0,0 @@
mod foo {
use extend::ext;
#[ext(pub)]
impl<T1, T2, T3> (T1, T2, T3) {
fn size(&self) -> usize {
3
}
}
}
fn main() {
use foo::TupleOfT1T2T3Ext;
assert_eq!(3, (0, 0, 0).size());
}

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

@ -1,17 +0,0 @@
use extend::ext;
#[ext]
impl Option<usize> {
fn foo() -> usize {
1
}
}
#[ext]
impl Option<i32> {
fn bar() -> i32 {
1
}
}
fn main() {}

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

@ -1,58 +0,0 @@
use extend::ext;
#[ext]
impl<'a> &'a str {
fn foo(self) {}
}
#[ext]
impl<T> [T; 3] {
fn foo(self) {}
}
#[ext]
impl *const i32 {
fn foo(self) {}
}
#[ext]
impl<T> [T] {
fn foo(&self) {}
}
#[ext]
impl<'a, T> &'a [T] {
fn foo(self) {}
}
#[ext]
impl (i32, i64) {
fn foo(self) {}
}
#[ext]
impl fn(i32) -> bool {
fn foo(self) {}
}
fn bare_fn(_: i32) -> bool {
false
}
#[ext]
impl dyn Send + Sync + 'static {}
fn main() {
"".foo();
[1, 2, 3].foo();
let ptr: *const i32 = &123;
ptr.foo();
&[1, 2, 3].foo();
(1i32, 1i64).foo();
(bare_fn as fn(i32) -> bool).foo();
}

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

@ -1,15 +0,0 @@
use extend::ext;
#[ext]
impl<'a, T: Clone> Vec<&'a T>
where
T: 'a + Copy,
{
fn size(&self) -> usize {
self.len()
}
}
fn main() {
assert_eq!(3, vec![&1, &2, &3].size());
}

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

@ -1,20 +0,0 @@
use extend::ext;
#[ext]
impl i32 {
fn add_one(&self) -> Self {
self + 1
}
fn foo() -> MyType {
MyType
}
}
#[derive(Debug, Eq, PartialEq)]
struct MyType;
fn main() {
assert_eq!(i32::foo(), MyType);
assert_eq!(1.add_one(), 2);
}

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

@ -1,33 +0,0 @@
#![allow(unused_variables)]
use extend::ext;
use std::iter::FromIterator;
#[ext]
impl<T, K, F, C> C
where
C: IntoIterator<Item = T>,
K: Eq,
F: Fn(&T) -> K,
{
fn group_by<Out>(self, f: F) -> Out
where
Out: FromIterator<(K, Vec<T>)>,
{
todo!()
}
fn group_by_and_map_values<Out, G, T2>(self, f: F, g: G) -> Out
where
G: Fn(T) -> T2 + Copy,
Out: FromIterator<(K, Vec<T2>)>,
{
todo!()
}
fn group_by_and_return_groups(self, f: F) -> Vec<Vec<T>> {
todo!()
}
}
fn main() {}

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

@ -1,13 +0,0 @@
use extend::ext;
#[ext]
impl i32 {
fn foo() {}
}
#[ext]
impl i64 {
fn bar() {}
}
fn main() {}

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

@ -1,13 +0,0 @@
use extend::ext;
#[ext(pub(crate), name = Foo)]
impl i32 {
fn foo() {}
}
#[ext(pub, name = Bar)]
impl i64 {
fn foo() {}
}
fn main() {}

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

@ -1,11 +0,0 @@
use extend::ext;
use std::marker::PhantomData;
struct Foo<T>(PhantomData<T>);
#[ext]
impl<T, K> T {
fn some_method(&self, _: Foo<K>) {}
}
fn main() {}

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

@ -1,15 +0,0 @@
mod a {
use extend::ext;
#[ext]
pub impl i32 {
fn foo() -> Foo { Foo }
}
pub struct Foo;
}
fn main() {
use a::i32Ext;
i32::foo();
}

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

@ -1,13 +0,0 @@
use extend::ext;
#[ext]
impl &i32 {
fn foo() {}
}
#[ext]
impl &mut i32 {
fn bar() {}
}
fn main() {}

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

@ -1,36 +0,0 @@
use extend::ext_sized;
#[ext_sized(name = One)]
impl i32 {
fn requires_sized(self) -> Option<Self> {
Some(self)
}
}
#[ext_sized(name = Two, supertraits = Default)]
impl i32 {
fn with_another_supertrait(self) -> Option<Self> {
Some(self)
}
}
#[ext_sized(name = Three, supertraits = Default + Clone + Copy)]
impl i32 {
fn multiple_supertraits(self) -> Option<Self> {
Some(self)
}
}
#[ext_sized(name = Four, supertraits = Sized)]
impl i32 {
fn already_sized(self) -> Option<Self> {
Some(self)
}
}
fn main() {
1.requires_sized();
1.with_another_supertrait();
1.multiple_supertraits();
1.already_sized();
}

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

@ -1,16 +0,0 @@
use extend::ext;
trait MyTrait {}
impl MyTrait for String {}
#[ext(supertraits = Default + Clone + MyTrait)]
impl String {
fn my_len(&self) -> usize {
self.len()
}
}
fn main() {
assert_eq!(String::new().my_len(), 0);
}

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

@ -1,15 +0,0 @@
mod a {
use extend::ext;
#[ext(pub)]
impl i32 {
fn foo() -> Foo { Foo }
}
pub struct Foo;
}
fn main() {
use a::i32Ext;
i32::foo();
}

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

@ -1 +0,0 @@
{"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}

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

@ -1,19 +0,0 @@
[package]
name = "uniffi-example-arithmetic"
edition = "2021"
version = "0.18.0"
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
license = "MPL-2.0"
publish = false
[lib]
crate-type = ["lib", "cdylib"]
name = "arithmetical"
[dependencies]
uniffi_macros = {path = "../../uniffi_macros"}
uniffi = {path = "../../uniffi", features=["builtin-bindgen"]}
thiserror = "1.0"
[build-dependencies]
uniffi_build = {path = "../../uniffi_build", features=["builtin-bindgen"]}

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

@ -1,7 +0,0 @@
/* 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/arithmetic.udl").unwrap();
}

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

@ -1,16 +0,0 @@
[Error]
enum ArithmeticError {
"IntegerOverflow",
};
namespace arithmetic {
[Throws=ArithmeticError]
u64 add(u64 a, u64 b);
[Throws=ArithmeticError]
u64 sub(u64 a, u64 b);
u64 div(u64 dividend, u64 divisor);
boolean equal(u64 a, u64 b);
};

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

@ -1,34 +0,0 @@
/* 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/. */
#[derive(Debug, thiserror::Error)]
pub enum ArithmeticError {
#[error("Integer overflow on an operation with {a} and {b}")]
IntegerOverflow { a: u64, b: u64 },
}
fn add(a: u64, b: u64) -> Result<u64> {
a.checked_add(b)
.ok_or(ArithmeticError::IntegerOverflow { a, b })
}
fn sub(a: u64, b: u64) -> Result<u64> {
a.checked_sub(b)
.ok_or(ArithmeticError::IntegerOverflow { a, b })
}
fn div(dividend: u64, divisor: u64) -> u64 {
if divisor == 0 {
panic!("Can't divide by zero");
}
dividend / divisor
}
fn equal(a: u64, b: u64) -> bool {
a == b
}
type Result<T, E = ArithmeticError> = std::result::Result<T, E>;
uniffi_macros::include_scaffolding!("arithmetic");

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

@ -1,29 +0,0 @@
import org.mozilla.uniffi.example.arithmetic.*;
assert(add(2u, 4u) == 6uL)
assert(add(4u, 8u) == 12uL)
try {
sub(0u, 2u)
throw RuntimeException("Should have thrown a IntegerOverflow exception!")
} catch (e: ArithmeticException) {
// It's okay!
}
assert(sub(4u, 2u) == 2uL)
assert(sub(8u, 4u) == 4uL)
assert(div(8u, 4u) == 2uL)
try {
div(8u, 0u)
throw RuntimeException("Should have panicked when dividing by zero")
} catch (e: InternalException) {
// It's okay!
}
assert(equal(2u, 2uL))
assert(equal(4u, 4uL))
assert(!equal(2u, 4uL))
assert(!equal(4u, 8uL))

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

@ -1,37 +0,0 @@
from arithmetic import *
try:
add(18446744073709551615, 1)
assert(not("Should have thrown a IntegerOverflow exception!"))
except ArithmeticError.IntegerOverflow:
# It's okay!
pass
assert add(2, 4) == 6
assert add(4, 8) == 12
try:
sub(0, 1)
assert(not("Should have thrown a IntegerOverflow exception!"))
except ArithmeticError.IntegerOverflow:
# It's okay!
pass
assert sub(4, 2) == 2
assert sub(8, 4) == 4
assert div(8, 4) == 2
try:
div(8, 0)
except InternalError:
# It's okay!
pass
else:
assert(not("Should have panicked when dividing by zero"))
assert equal(2, 2)
assert equal(4, 4)
assert not equal(2, 4)
assert not equal(4, 8)

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

@ -1,31 +0,0 @@
# frozen_string_literal: true
require 'test/unit'
require 'arithmetic'
include Test::Unit::Assertions
assert_raise Arithmetic::ArithmeticError::IntegerOverflow do
Arithmetic.add 18_446_744_073_709_551_615, 1
end
assert_equal Arithmetic.add(2, 4), 6
assert_equal Arithmetic.add(4, 8), 12
assert_raise Arithmetic::ArithmeticError::IntegerOverflow do
Arithmetic.sub 0, 1
end
assert_equal Arithmetic.sub(4, 2), 2
assert_equal Arithmetic.sub(8, 4), 4
assert_equal Arithmetic.div(8, 4), 2
assert_raise Arithmetic::InternalError do
Arithmetic.div 8, 0
end
assert Arithmetic.equal(2, 2)
assert Arithmetic.equal(4, 4)
assert !Arithmetic.equal(2, 4)
assert !Arithmetic.equal(4, 8)

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

@ -1,32 +0,0 @@
import arithmetic
do {
let _ = try add(a: 18446744073709551615, b: 1)
fatalError("Should have thrown a IntegerOverflow exception!")
} catch ArithmeticError.IntegerOverflow {
// It's okay!
}
assert(try! add(a: 2, b: 4) == 6, "add work")
assert(try! add(a: 4, b: 8) == 12, "add work")
do {
let _ = try sub(a: 0, b: 1)
fatalError("Should have thrown a IntegerOverflow exception!")
} catch ArithmeticError.IntegerOverflow {
// It's okay!
}
assert(try! sub(a: 4, b: 2) == 2, "sub work")
assert(try! sub(a: 8, b: 4) == 4, "sub work")
assert(div(dividend: 8, divisor: 4) == 2, "div works")
// We can't test panicking in Swift because we force unwrap the error in
// `div`, which we can't catch.
assert(equal(a: 2, b: 2), "equal works")
assert(equal(a: 4, b: 4), "equal works")
assert(!equal(a: 2, b: 4), "non-equal works")
assert(!equal(a: 4, b: 8), "non-equal works")

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

@ -1,9 +0,0 @@
uniffi_macros::build_foreign_language_testcases!(
["src/arithmetic.udl",],
[
"tests/bindings/test_arithmetic.rb",
"tests/bindings/test_arithmetic.py",
"tests/bindings/test_arithmetic.kts",
"tests/bindings/test_arithmetic.swift",
]
);

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

@ -1,12 +0,0 @@
[bindings.kotlin]
package_name = "org.mozilla.uniffi.example.arithmetic"
cdylib_name = "arithmetical"
[bindings.python]
cdylib_name = "arithmetical"
[bindings.ruby]
cdylib_name = "arithmetical"
[bindings.swift]
cdylib_name = "arithmetical"

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

@ -1 +0,0 @@
{"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}

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

@ -1,18 +0,0 @@
[package]
name = "uniffi-example-geometry"
edition = "2021"
version = "0.18.0"
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
license = "MPL-2.0"
publish = false
[lib]
crate-type = ["lib", "cdylib"]
name = "uniffi_geometry"
[dependencies]
uniffi_macros = {path = "../../uniffi_macros"}
uniffi = {path = "../../uniffi", features=["builtin-bindgen"]}
[build-dependencies]
uniffi_build = {path = "../../uniffi_build", features=["builtin-bindgen"]}

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

@ -1,7 +0,0 @@
/* 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/geometry.udl").unwrap();
}

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

@ -1,15 +0,0 @@
namespace geometry {
double gradient(Line ln);
Point? intersection(Line ln1, Line ln2);
};
dictionary Point {
double coord_x;
double coord_y;
};
dictionary Line {
Point start;
Point end;
};

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

@ -1,47 +0,0 @@
/* 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/. */
// https://rust-lang.github.io/rust-clippy/master/index.html#float_cmp
// Silence, clippy!
const EPSILON: f64 = 0.0001f64;
#[derive(Debug, Clone)]
pub struct Point {
coord_x: f64,
coord_y: f64,
}
#[derive(Debug, Clone)]
pub struct Line {
start: Point,
end: Point,
}
pub fn gradient(ln: Line) -> f64 {
let rise = ln.end.coord_y - ln.start.coord_y;
let run = ln.end.coord_x - ln.start.coord_x;
rise / run
}
pub fn intersection(ln1: Line, ln2: Line) -> Option<Point> {
// TODO: yuck, should be able to take &Line as argument here
// and have rust figure it out with a bunch of annotations...
let g1 = gradient(ln1.clone());
let z1 = ln1.start.coord_y - g1 * ln1.start.coord_x;
let g2 = gradient(ln2.clone());
let z2 = ln2.start.coord_y - g2 * ln2.start.coord_x;
// Parallel lines do not intersect.
if (g1 - g2).abs() < EPSILON {
return None;
}
// Otherwise, they intersect at this fancy calculation that
// I found on wikipedia.
let x = (z2 - z1) / (g1 - g2);
Some(Point {
coord_x: x,
coord_y: g1 * x + z1,
})
}
include!(concat!(env!("OUT_DIR"), "/geometry.uniffi.rs"));

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

@ -1,10 +0,0 @@
import uniffi.geometry.*;
val ln1 = Line(Point(0.0,0.0), Point(1.0,2.0))
val ln2 = Line(Point(1.0,1.0), Point(2.0,2.0))
assert( gradient(ln1) == 2.0 )
assert( gradient(ln2) == 1.0 )
assert( intersection(ln1, ln2) == Point(0.0, 0.0) )
assert( intersection(ln1, ln1) == null )

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

@ -1,10 +0,0 @@
from geometry import *
ln1 = Line(Point(0,0), Point(1,2))
ln2 = Line(Point(1,1), Point(2,2))
assert gradient(ln1) == 2
assert gradient(ln2) == 1
assert intersection(ln1, ln2) == Point(0, 0)
assert intersection(ln1, ln1) is None

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

@ -1,16 +0,0 @@
# frozen_string_literal: true
require 'test/unit'
require 'geometry'
include Test::Unit::Assertions
include Geometry
ln1 = Line.new(Point.new(0.0, 0.0), Point.new(1.0, 2.0))
ln2 = Line.new(Point.new(1.0, 1.0), Point.new(2.0, 2.0))
assert_equal Geometry.gradient(ln1), 2
assert_equal Geometry.gradient(ln2), 1
assert_equal Geometry.intersection(ln1, ln2), Point.new(0, 0)
assert Geometry.intersection(ln1, ln1).nil?

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

@ -1,10 +0,0 @@
import geometry
let ln1 = Line(start: Point(coordX: 0, coordY: 0), end: Point(coordX: 1, coordY: 2))
let ln2 = Line(start: Point(coordX: 1, coordY: 1), end: Point(coordX: 2, coordY: 2))
assert(gradient(ln: ln1) == 2.0)
assert(gradient(ln: ln2) == 1.0)
assert(intersection(ln1: ln1, ln2: ln2) == Point(coordX: 0, coordY: 0))
assert(intersection(ln1: ln1, ln2: ln1) == nil)

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

@ -1,9 +0,0 @@
uniffi_macros::build_foreign_language_testcases!(
["src/geometry.udl",],
[
"tests/bindings/test_geometry.py",
"tests/bindings/test_geometry.rb",
"tests/bindings/test_geometry.kts",
"tests/bindings/test_geometry.swift",
]
);

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

@ -1 +0,0 @@
[bindings.swift]

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

@ -1 +0,0 @@
{"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}

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

@ -1,18 +0,0 @@
[package]
name = "uniffi-example-rondpoint"
edition = "2021"
version = "0.18.0"
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
license = "MPL-2.0"
publish = false
[lib]
crate-type = ["lib", "cdylib"]
name = "uniffi_rondpoint"
[dependencies]
uniffi_macros = {path = "../../uniffi_macros"}
uniffi = {path = "../../uniffi", features=["builtin-bindgen"]}
[build-dependencies]
uniffi_build = {path = "../../uniffi_build", features=["builtin-bindgen"]}

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

@ -1,7 +0,0 @@
/* 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/rondpoint.udl").unwrap();
}

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

@ -1,293 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct Dictionnaire {
un: Enumeration,
deux: bool,
petit_nombre: u8,
gros_nombre: u64,
}
#[derive(Debug, Clone)]
pub struct DictionnaireNombres {
petit_nombre: u8,
court_nombre: u16,
nombre_simple: u32,
gros_nombre: u64,
}
#[derive(Debug, Clone)]
pub struct DictionnaireNombresSignes {
petit_nombre: i8,
court_nombre: i16,
nombre_simple: i32,
gros_nombre: i64,
}
#[derive(Debug, Clone)]
pub enum Enumeration {
Un,
Deux,
Trois,
}
#[derive(Debug, Clone)]
pub enum EnumerationAvecDonnees {
Zero,
Un { premier: u32 },
Deux { premier: u32, second: String },
}
#[allow(non_camel_case_types)]
#[allow(non_snake_case)]
pub struct minusculeMAJUSCULEDict {
minusculeMAJUSCULEField: bool,
}
#[allow(non_camel_case_types)]
pub enum minusculeMAJUSCULEEnum {
minusculeMAJUSCULEVariant,
}
fn copie_enumeration(e: Enumeration) -> Enumeration {
e
}
fn copie_enumerations(e: Vec<Enumeration>) -> Vec<Enumeration> {
e
}
fn copie_carte(
e: HashMap<String, EnumerationAvecDonnees>,
) -> HashMap<String, EnumerationAvecDonnees> {
e
}
fn copie_dictionnaire(d: Dictionnaire) -> Dictionnaire {
d
}
fn switcheroo(b: bool) -> bool {
!b
}
// Test that values can traverse both ways across the FFI.
// Even if roundtripping works, it's possible we have
// symmetrical errors that cancel each other out.
#[derive(Debug, Clone)]
struct Retourneur;
impl Retourneur {
fn new() -> Self {
Retourneur
}
fn identique_i8(&self, value: i8) -> i8 {
value
}
fn identique_u8(&self, value: u8) -> u8 {
value
}
fn identique_i16(&self, value: i16) -> i16 {
value
}
fn identique_u16(&self, value: u16) -> u16 {
value
}
fn identique_i32(&self, value: i32) -> i32 {
value
}
fn identique_u32(&self, value: u32) -> u32 {
value
}
fn identique_i64(&self, value: i64) -> i64 {
value
}
fn identique_u64(&self, value: u64) -> u64 {
value
}
fn identique_float(&self, value: f32) -> f32 {
value
}
fn identique_double(&self, value: f64) -> f64 {
value
}
fn identique_boolean(&self, value: bool) -> bool {
value
}
fn identique_string(&self, value: String) -> String {
value
}
fn identique_nombres_signes(
&self,
value: DictionnaireNombresSignes,
) -> DictionnaireNombresSignes {
value
}
fn identique_nombres(&self, value: DictionnaireNombres) -> DictionnaireNombres {
value
}
fn identique_optionneur_dictionnaire(
&self,
value: OptionneurDictionnaire,
) -> OptionneurDictionnaire {
value
}
}
#[derive(Debug, Clone)]
struct Stringifier;
#[allow(dead_code)]
impl Stringifier {
fn new() -> Self {
Stringifier
}
fn to_string_i8(&self, value: i8) -> String {
value.to_string()
}
fn to_string_u8(&self, value: u8) -> String {
value.to_string()
}
fn to_string_i16(&self, value: i16) -> String {
value.to_string()
}
fn to_string_u16(&self, value: u16) -> String {
value.to_string()
}
fn to_string_i32(&self, value: i32) -> String {
value.to_string()
}
fn to_string_u32(&self, value: u32) -> String {
value.to_string()
}
fn to_string_i64(&self, value: i64) -> String {
value.to_string()
}
fn to_string_u64(&self, value: u64) -> String {
value.to_string()
}
fn to_string_float(&self, value: f32) -> String {
value.to_string()
}
fn to_string_double(&self, value: f64) -> String {
value.to_string()
}
fn to_string_boolean(&self, value: bool) -> String {
value.to_string()
}
fn well_known_string(&self, value: String) -> String {
format!("uniffi 💚 {}!", value)
}
}
#[derive(Debug, Clone)]
struct Optionneur;
impl Optionneur {
fn new() -> Self {
Optionneur
}
fn sinon_string(&self, value: String) -> String {
value
}
fn sinon_null(&self, value: Option<String>) -> Option<String> {
value
}
fn sinon_boolean(&self, value: bool) -> bool {
value
}
fn sinon_sequence(&self, value: Vec<String>) -> Vec<String> {
value
}
fn sinon_zero(&self, value: Option<i32>) -> Option<i32> {
value
}
fn sinon_u8_dec(&self, value: u8) -> u8 {
value
}
fn sinon_i8_dec(&self, value: i8) -> i8 {
value
}
fn sinon_u16_dec(&self, value: u16) -> u16 {
value
}
fn sinon_i16_dec(&self, value: i16) -> i16 {
value
}
fn sinon_u32_dec(&self, value: u32) -> u32 {
value
}
fn sinon_i32_dec(&self, value: i32) -> i32 {
value
}
fn sinon_u64_dec(&self, value: u64) -> u64 {
value
}
fn sinon_i64_dec(&self, value: i64) -> i64 {
value
}
fn sinon_u8_hex(&self, value: u8) -> u8 {
value
}
fn sinon_i8_hex(&self, value: i8) -> i8 {
value
}
fn sinon_u16_hex(&self, value: u16) -> u16 {
value
}
fn sinon_i16_hex(&self, value: i16) -> i16 {
value
}
fn sinon_u32_hex(&self, value: u32) -> u32 {
value
}
fn sinon_i32_hex(&self, value: i32) -> i32 {
value
}
fn sinon_u64_hex(&self, value: u64) -> u64 {
value
}
fn sinon_i64_hex(&self, value: i64) -> i64 {
value
}
fn sinon_u32_oct(&self, value: u32) -> u32 {
value
}
fn sinon_f32(&self, value: f32) -> f32 {
value
}
fn sinon_f64(&self, value: f64) -> f64 {
value
}
fn sinon_enum(&self, value: Enumeration) -> Enumeration {
value
}
}
pub struct OptionneurDictionnaire {
i8_var: i8,
u8_var: u8,
i16_var: i16,
u16_var: u16,
i32_var: i32,
u32_var: u32,
i64_var: i64,
u64_var: u64,
float_var: f32,
double_var: f64,
boolean_var: bool,
string_var: String,
list_var: Vec<String>,
enumeration_var: Enumeration,
dictionnaire_var: Option<minusculeMAJUSCULEEnum>,
}
include!(concat!(env!("OUT_DIR"), "/rondpoint.uniffi.rs"));

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

@ -1,146 +0,0 @@
namespace rondpoint {
Dictionnaire copie_dictionnaire(Dictionnaire d);
Enumeration copie_enumeration(Enumeration e);
sequence<Enumeration> copie_enumerations(sequence<Enumeration> e);
record<DOMString, EnumerationAvecDonnees> copie_carte(record<DOMString, EnumerationAvecDonnees> c);
boolean switcheroo(boolean b);
};
dictionary minusculeMAJUSCULEDict {
boolean minusculeMAJUSCULEField;
};
enum minusculeMAJUSCULEEnum {
"minusculeMAJUSCULEVariant",
};
enum Enumeration {
"Un",
"Deux",
"Trois",
};
[Enum]
interface EnumerationAvecDonnees {
Zero();
Un(u32 premier);
Deux(u32 premier, string second);
};
dictionary Dictionnaire {
Enumeration un;
boolean deux;
u8 petit_nombre;
u64 gros_nombre;
};
dictionary DictionnaireNombres {
u8 petit_nombre;
u16 court_nombre;
u32 nombre_simple;
u64 gros_nombre;
};
dictionary DictionnaireNombresSignes {
i8 petit_nombre;
i16 court_nombre;
i32 nombre_simple;
i64 gros_nombre;
};
interface Retourneur {
constructor();
i8 identique_i8(i8 value);
u8 identique_u8(u8 value);
i16 identique_i16(i16 value);
u16 identique_u16(u16 value);
i32 identique_i32(i32 value);
u32 identique_u32(u32 value);
i64 identique_i64(i64 value);
u64 identique_u64(u64 value);
float identique_float(float value);
double identique_double(double value);
boolean identique_boolean(boolean value);
string identique_string(string value);
DictionnaireNombresSignes identique_nombres_signes(DictionnaireNombresSignes value);
DictionnaireNombres identique_nombres(DictionnaireNombres value);
OptionneurDictionnaire identique_optionneur_dictionnaire(OptionneurDictionnaire value);
};
interface Stringifier {
constructor();
string well_known_string(string value);
string to_string_i8(i8 value);
string to_string_u8(u8 value);
string to_string_i16(i16 value);
string to_string_u16(u16 value);
string to_string_i32(i32 value);
string to_string_u32(u32 value);
string to_string_i64(i64 value);
string to_string_u64(u64 value);
string to_string_float(float value);
string to_string_double(double value);
string to_string_boolean(boolean value);
};
interface Optionneur {
constructor();
boolean sinon_boolean(optional boolean value = false);
string sinon_string(optional string value = "default");
sequence<string> sinon_sequence(optional sequence<string> value = []);
// Either sides of nullable.
string? sinon_null(optional string? value = null);
i32? sinon_zero(optional i32? value = 0);
// Decimal integers, all 42.
u8 sinon_u8_dec(optional u8 value = 42);
i8 sinon_i8_dec(optional i8 value = -42);
u16 sinon_u16_dec(optional u16 value = 42);
i16 sinon_i16_dec(optional i16 value = 42);
u32 sinon_u32_dec(optional u32 value = 42);
i32 sinon_i32_dec(optional i32 value = 42);
u64 sinon_u64_dec(optional u64 value = 42);
i64 sinon_i64_dec(optional i64 value = 42);
// Hexadecimal, including negatgives.
u8 sinon_u8_hex(optional u8 value = 0xff);
i8 sinon_i8_hex(optional i8 value = -0x7f);
u16 sinon_u16_hex(optional u16 value = 0xffff);
i16 sinon_i16_hex(optional i16 value = 0x7f);
u32 sinon_u32_hex(optional u32 value = 0xffffffff);
i32 sinon_i32_hex(optional i32 value = 0x7fffffff);
u64 sinon_u64_hex(optional u64 value = 0xffffffffffffffff);
i64 sinon_i64_hex(optional i64 value = 0x7fffffffffffffff);
// Octal, FWIW.
u32 sinon_u32_oct(optional u32 value = 0755);
// Floats
f32 sinon_f32(optional f32 value = 42.0);
f64 sinon_f64(optional f64 value = 42.1);
// Enums, which we have to treat as strings in the UDL frontend.
Enumeration sinon_enum(optional Enumeration value = "Trois");
};
dictionary OptionneurDictionnaire {
i8 i8_var = -8;
u8 u8_var = 8;
i16 i16_var = -0x10;
u16 u16_var = 0x10;
i32 i32_var = -32;
u32 u32_var = 32;
i64 i64_var = -64;
u64 u64_var = 64;
float float_var = 4.0;
double double_var = 8.0;
boolean boolean_var = true;
string string_var = "default";
sequence<string> list_var = [];
Enumeration enumeration_var = "DEUX";
minusculeMAJUSCULEEnum? dictionnaire_var = null;
};

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

@ -1,250 +0,0 @@
import uniffi.rondpoint.*
val dico = Dictionnaire(Enumeration.DEUX, true, 0u, 123456789u)
val copyDico = copieDictionnaire(dico)
assert(dico == copyDico)
assert(copieEnumeration(Enumeration.DEUX) == Enumeration.DEUX)
assert(copieEnumerations(listOf(Enumeration.UN, Enumeration.DEUX)) == listOf(Enumeration.UN, Enumeration.DEUX))
assert(copieCarte(mapOf(
"0" to EnumerationAvecDonnees.Zero,
"1" to EnumerationAvecDonnees.Un(1u),
"2" to EnumerationAvecDonnees.Deux(2u, "deux")
)) == mapOf(
"0" to EnumerationAvecDonnees.Zero,
"1" to EnumerationAvecDonnees.Un(1u),
"2" to EnumerationAvecDonnees.Deux(2u, "deux")
))
val var1: EnumerationAvecDonnees = EnumerationAvecDonnees.Zero
val var2: EnumerationAvecDonnees = EnumerationAvecDonnees.Un(1u)
val var3: EnumerationAvecDonnees = EnumerationAvecDonnees.Un(2u)
assert(var1 != var2)
assert(var2 != var3)
assert(var1 == EnumerationAvecDonnees.Zero)
assert(var1 != EnumerationAvecDonnees.Un(1u))
assert(var2 == EnumerationAvecDonnees.Un(1u))
assert(switcheroo(false))
// Test the roundtrip across the FFI.
// This shows that the values we send come back in exactly the same state as we sent them.
// i.e. it shows that lowering from kotlin and lifting into rust is symmetrical with
// lowering from rust and lifting into kotlin.
val rt = Retourneur()
fun <T> List<T>.affirmAllerRetour(fn: (T) -> T) {
this.forEach { v ->
assert(fn.invoke(v) == v) { "$fn($v)" }
}
}
// Booleans
listOf(true, false).affirmAllerRetour(rt::identiqueBoolean)
// Bytes.
listOf(Byte.MIN_VALUE, Byte.MAX_VALUE).affirmAllerRetour(rt::identiqueI8)
listOf(0x00, 0xFF).map { it.toUByte() }.affirmAllerRetour(rt::identiqueU8)
// Shorts
listOf(Short.MIN_VALUE, Short.MAX_VALUE).affirmAllerRetour(rt::identiqueI16)
listOf(0x0000, 0xFFFF).map { it.toUShort() }.affirmAllerRetour(rt::identiqueU16)
// Ints
listOf(0, 1, -1, Int.MIN_VALUE, Int.MAX_VALUE).affirmAllerRetour(rt::identiqueI32)
listOf(0x00000000, 0xFFFFFFFF).map { it.toUInt() }.affirmAllerRetour(rt::identiqueU32)
// Longs
listOf(0L, 1L, -1L, Long.MIN_VALUE, Long.MAX_VALUE).affirmAllerRetour(rt::identiqueI64)
listOf(0u, 1u, ULong.MIN_VALUE, ULong.MAX_VALUE).affirmAllerRetour(rt::identiqueU64)
// Floats
listOf(0.0F, 0.5F, 0.25F, Float.MIN_VALUE, Float.MAX_VALUE).affirmAllerRetour(rt::identiqueFloat)
// Doubles
listOf(0.0, 1.0, Double.MIN_VALUE, Double.MAX_VALUE).affirmAllerRetour(rt::identiqueDouble)
// Strings
listOf("", "abc", "null\u0000byte", "été", "ښي لاس ته لوستلو لوستل", "😻emoji 👨👧👦multi-emoji, 🇨🇭a flag, a canal, panama")
.affirmAllerRetour(rt::identiqueString)
listOf(-1, 0, 1).map { DictionnaireNombresSignes(it.toByte(), it.toShort(), it.toInt(), it.toLong()) }
.affirmAllerRetour(rt::identiqueNombresSignes)
listOf(0, 1).map { DictionnaireNombres(it.toUByte(), it.toUShort(), it.toUInt(), it.toULong()) }
.affirmAllerRetour(rt::identiqueNombres)
rt.destroy()
// Test one way across the FFI.
//
// We send one representation of a value to lib.rs, and it transforms it into another, a string.
// lib.rs sends the string back, and then we compare here in kotlin.
//
// This shows that the values are transformed into strings the same way in both kotlin and rust.
// i.e. if we assume that the string return works (we test this assumption elsewhere)
// we show that lowering from kotlin and lifting into rust has values that both kotlin and rust
// both stringify in the same way. i.e. the same values.
//
// If we roundtripping proves the symmetry of our lowering/lifting from here to rust, and lowering/lifting from rust t here,
// and this convinces us that lowering/lifting from here to rust is correct, then
// together, we've shown the correctness of the return leg.
val st = Stringifier()
typealias StringyEquals<T> = (observed: String, expected: T) -> Boolean
fun <T> List<T>.affirmEnchaine(
fn: (T) -> String,
equals: StringyEquals<T> = { obs, exp -> obs == exp.toString() }
) {
this.forEach { exp ->
val obs = fn.invoke(exp)
assert(equals(obs, exp)) { "$fn($exp): observed=$obs, expected=$exp" }
}
}
// Test the efficacy of the string transport from rust. If this fails, but everything else
// works, then things are very weird.
val wellKnown = st.wellKnownString("kotlin")
assert("uniffi 💚 kotlin!" == wellKnown) { "wellKnownString 'uniffi 💚 kotlin!' == '$wellKnown'" }
// Booleans
listOf(true, false).affirmEnchaine(st::toStringBoolean)
// Bytes.
listOf(Byte.MIN_VALUE, Byte.MAX_VALUE).affirmEnchaine(st::toStringI8)
listOf(UByte.MIN_VALUE, UByte.MAX_VALUE).affirmEnchaine(st::toStringU8)
// Shorts
listOf(Short.MIN_VALUE, Short.MAX_VALUE).affirmEnchaine(st::toStringI16)
listOf(UShort.MIN_VALUE, UShort.MAX_VALUE).affirmEnchaine(st::toStringU16)
// Ints
listOf(0, 1, -1, Int.MIN_VALUE, Int.MAX_VALUE).affirmEnchaine(st::toStringI32)
listOf(0u, 1u, UInt.MIN_VALUE, UInt.MAX_VALUE).affirmEnchaine(st::toStringU32)
// Longs
listOf(0L, 1L, -1L, Long.MIN_VALUE, Long.MAX_VALUE).affirmEnchaine(st::toStringI64)
listOf(0u, 1u, ULong.MIN_VALUE, ULong.MAX_VALUE).affirmEnchaine(st::toStringU64)
// Floats
// MIN_VAUE is 1.4E-45. Accuracy and formatting get weird at small sizes.
listOf(0.0F, 1.0F, -1.0F, Float.MIN_VALUE, Float.MAX_VALUE).affirmEnchaine(st::toStringFloat) { s, n -> s.toFloat() == n }
// Doubles
// MIN_VALUE is 4.9E-324. Accuracy and formatting get weird at small sizes.
listOf(0.0, 1.0, -1.0, Double.MIN_VALUE, Double.MAX_VALUE).affirmEnchaine(st::toStringDouble) { s, n -> s.toDouble() == n }
st.destroy()
// Prove to ourselves that default arguments are being used.
// Step 1: call the methods without arguments, and check against the UDL.
val op = Optionneur()
assert(op.sinonString() == "default")
assert(op.sinonBoolean() == false)
assert(op.sinonSequence() == listOf<String>())
// optionals
assert(op.sinonNull() == null)
assert(op.sinonZero() == 0)
// decimal integers
assert(op.sinonI8Dec() == (-42).toByte())
assert(op.sinonU8Dec() == 42.toUByte())
assert(op.sinonI16Dec() == 42.toShort())
assert(op.sinonU16Dec() == 42.toUShort())
assert(op.sinonI32Dec() == 42)
assert(op.sinonU32Dec() == 42.toUInt())
assert(op.sinonI64Dec() == 42L)
assert(op.sinonU64Dec() == 42uL)
// hexadecimal integers
assert(op.sinonI8Hex() == (-0x7f).toByte())
assert(op.sinonU8Hex() == 0xff.toUByte())
assert(op.sinonI16Hex() == 0x7f.toShort())
assert(op.sinonU16Hex() == 0xffff.toUShort())
assert(op.sinonI32Hex() == 0x7fffffff)
assert(op.sinonU32Hex() == 0xffffffff.toUInt())
assert(op.sinonI64Hex() == 0x7fffffffffffffffL)
assert(op.sinonU64Hex() == 0xffffffffffffffffuL)
// octal integers
assert(op.sinonU32Oct() == 493u) // 0o755
// floats
assert(op.sinonF32() == 42.0f)
assert(op.sinonF64() == 42.1)
// enums
assert(op.sinonEnum() == Enumeration.TROIS)
// Step 2. Convince ourselves that if we pass something else, then that changes the output.
// We have shown something coming out of the sinon methods, but without eyeballing the Rust
// we can't be sure that the arguments will change the return value.
listOf("foo", "bar").affirmAllerRetour(op::sinonString)
listOf(true, false).affirmAllerRetour(op::sinonBoolean)
listOf(listOf("a", "b"), listOf()).affirmAllerRetour(op::sinonSequence)
// optionals
listOf("0", "1").affirmAllerRetour(op::sinonNull)
listOf(0, 1).affirmAllerRetour(op::sinonZero)
// integers
listOf(0, 1).map { it.toUByte() }.affirmAllerRetour(op::sinonU8Dec)
listOf(0, 1).map { it.toByte() }.affirmAllerRetour(op::sinonI8Dec)
listOf(0, 1).map { it.toUShort() }.affirmAllerRetour(op::sinonU16Dec)
listOf(0, 1).map { it.toShort() }.affirmAllerRetour(op::sinonI16Dec)
listOf(0, 1).map { it.toUInt() }.affirmAllerRetour(op::sinonU32Dec)
listOf(0, 1).map { it.toInt() }.affirmAllerRetour(op::sinonI32Dec)
listOf(0, 1).map { it.toULong() }.affirmAllerRetour(op::sinonU64Dec)
listOf(0, 1).map { it.toLong() }.affirmAllerRetour(op::sinonI64Dec)
listOf(0, 1).map { it.toUByte() }.affirmAllerRetour(op::sinonU8Hex)
listOf(0, 1).map { it.toByte() }.affirmAllerRetour(op::sinonI8Hex)
listOf(0, 1).map { it.toUShort() }.affirmAllerRetour(op::sinonU16Hex)
listOf(0, 1).map { it.toShort() }.affirmAllerRetour(op::sinonI16Hex)
listOf(0, 1).map { it.toUInt() }.affirmAllerRetour(op::sinonU32Hex)
listOf(0, 1).map { it.toInt() }.affirmAllerRetour(op::sinonI32Hex)
listOf(0, 1).map { it.toULong() }.affirmAllerRetour(op::sinonU64Hex)
listOf(0, 1).map { it.toLong() }.affirmAllerRetour(op::sinonI64Hex)
listOf(0, 1).map { it.toUInt() }.affirmAllerRetour(op::sinonU32Oct)
// floats
listOf(0.0f, 1.0f).affirmAllerRetour(op::sinonF32)
listOf(0.0, 1.0).affirmAllerRetour(op::sinonF64)
// enums
Enumeration.values().toList().affirmAllerRetour(op::sinonEnum)
op.destroy()
// Testing defaulting properties in record types.
val defaultes = OptionneurDictionnaire()
val explicite = OptionneurDictionnaire(
i8Var = -8,
u8Var = 8u,
i16Var = -16,
u16Var = 0x10u,
i32Var = -32,
u32Var = 32u,
i64Var = -64L,
u64Var = 64uL,
floatVar = 4.0f,
doubleVar = 8.0,
booleanVar = true,
stringVar = "default",
listVar = listOf(),
enumerationVar = Enumeration.DEUX,
dictionnaireVar = null
)
assert(defaultes == explicite)
// …and makes sure they travel across and back the FFI.
val rt2 = Retourneur()
listOf(defaultes).affirmAllerRetour(rt2::identiqueOptionneurDictionnaire)
rt2.destroy()

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

@ -1,146 +0,0 @@
import sys
import ctypes
from rondpoint import *
dico = Dictionnaire(Enumeration.DEUX, True, 0, 123456789)
copyDico = copie_dictionnaire(dico)
assert dico == copyDico
assert copie_enumeration(Enumeration.DEUX) == Enumeration.DEUX
assert copie_enumerations([Enumeration.UN, Enumeration.DEUX]) == [Enumeration.UN, Enumeration.DEUX]
assert copie_carte({
"0": EnumerationAvecDonnees.ZERO(),
"1": EnumerationAvecDonnees.UN(1),
"2": EnumerationAvecDonnees.DEUX(2, "deux"),
}) == {
"0": EnumerationAvecDonnees.ZERO(),
"1": EnumerationAvecDonnees.UN(1),
"2": EnumerationAvecDonnees.DEUX(2, "deux"),
}
assert switcheroo(False) is True
assert EnumerationAvecDonnees.ZERO() != EnumerationAvecDonnees.UN(1)
assert EnumerationAvecDonnees.UN(1) == EnumerationAvecDonnees.UN(1)
assert EnumerationAvecDonnees.UN(1) != EnumerationAvecDonnees.UN(2)
# Test the roundtrip across the FFI.
# This shows that the values we send come back in exactly the same state as we sent them.
# i.e. it shows that lowering from python and lifting into rust is symmetrical with
# lowering from rust and lifting into python.
rt = Retourneur()
def affirmAllerRetour(vals, identique):
for v in vals:
id_v = identique(v)
assert id_v == v, f"Round-trip failure: {v} => {id_v}"
MIN_I8 = -1 * 2**7
MAX_I8 = 2**7 - 1
MIN_I16 = -1 * 2**15
MAX_I16 = 2**15 - 1
MIN_I32 = -1 * 2**31
MAX_I32 = 2**31 - 1
MIN_I64 = -1 * 2**31
MAX_I64 = 2**31 - 1
# Python floats are always doubles, so won't round-trip through f32 correctly.
# This truncates them appropriately.
F32_ONE_THIRD = ctypes.c_float(1.0 / 3).value
# Booleans
affirmAllerRetour([True, False], rt.identique_boolean)
# Bytes.
affirmAllerRetour([MIN_I8, -1, 0, 1, MAX_I8], rt.identique_i8)
affirmAllerRetour([0x00, 0x12, 0xFF], rt.identique_u8)
# Shorts
affirmAllerRetour([MIN_I16, -1, 0, 1, MAX_I16], rt.identique_i16)
affirmAllerRetour([0x0000, 0x1234, 0xFFFF], rt.identique_u16)
# Ints
affirmAllerRetour([MIN_I32, -1, 0, 1, MAX_I32], rt.identique_i32)
affirmAllerRetour([0x00000000, 0x12345678, 0xFFFFFFFF], rt.identique_u32)
# Longs
affirmAllerRetour([MIN_I64, -1, 0, 1, MAX_I64], rt.identique_i64)
affirmAllerRetour([0x0000000000000000, 0x1234567890ABCDEF, 0xFFFFFFFFFFFFFFFF], rt.identique_u64)
# Floats
affirmAllerRetour([0.0, 0.5, 0.25, 1.0, F32_ONE_THIRD], rt.identique_float)
# Doubles
affirmAllerRetour(
[0.0, 0.5, 0.25, 1.0, 1.0 / 3, sys.float_info.max, sys.float_info.min],
rt.identique_double
)
# Strings
affirmAllerRetour(
["", "abc", "été", "ښي لاس ته لوستلو لوستل", "😻emoji 👨👧👦multi-emoji, 🇨🇭a flag, a canal, panama"],
rt.identique_string
)
# Test one way across the FFI.
#
# We send one representation of a value to lib.rs, and it transforms it into another, a string.
# lib.rs sends the string back, and then we compare here in python.
#
# This shows that the values are transformed into strings the same way in both python and rust.
# i.e. if we assume that the string return works (we test this assumption elsewhere)
# we show that lowering from python and lifting into rust has values that both python and rust
# both stringify in the same way. i.e. the same values.
#
# If we roundtripping proves the symmetry of our lowering/lifting from here to rust, and lowering/lifting from rust to here,
# and this convinces us that lowering/lifting from here to rust is correct, then
# together, we've shown the correctness of the return leg.
st = Stringifier()
def affirmEnchaine(vals, toString, rustyStringify=lambda v: str(v).lower()):
for v in vals:
str_v = toString(v)
assert rustyStringify(v) == str_v, f"String compare error {v} => {str_v}"
# Test the efficacy of the string transport from rust. If this fails, but everything else
# works, then things are very weird.
wellKnown = st.well_known_string("python")
assert "uniffi 💚 python!" == wellKnown
# Booleans
affirmEnchaine([True, False], st.to_string_boolean)
# Bytes.
affirmEnchaine([MIN_I8, -1, 0, 1, MAX_I8], st.to_string_i8)
affirmEnchaine([0x00, 0x12, 0xFF], st.to_string_u8)
# Shorts
affirmEnchaine([MIN_I16, -1, 0, 1, MAX_I16], st.to_string_i16)
affirmEnchaine([0x0000, 0x1234, 0xFFFF], st.to_string_u16)
# Ints
affirmEnchaine([MIN_I32, -1, 0, 1, MAX_I32], st.to_string_i32)
affirmEnchaine([0x00000000, 0x12345678, 0xFFFFFFFF], st.to_string_u32)
# Longs
affirmEnchaine([MIN_I64, -1, 0, 1, MAX_I64], st.to_string_i64)
affirmEnchaine([0x0000000000000000, 0x1234567890ABCDEF, 0xFFFFFFFFFFFFFFFF], st.to_string_u64)
# Floats
def rustyFloatToStr(v):
"""Stringify a float in the same way that rust seems to."""
# Rust doesn't include the decimal part of whole enumber floats when stringifying.
if int(v) == v:
return str(int(v))
return str(v)
affirmEnchaine([0.0, 0.5, 0.25, 1.0], st.to_string_float, rustyFloatToStr)
assert st.to_string_float(F32_ONE_THIRD) == "0.33333334" # annoyingly different string repr
# Doubles
# TODO: float_info.max/float_info.min don't stringify-roundtrip properly yet, TBD.
affirmEnchaine(
[0.0, 0.5, 0.25, 1.0, 1.0 / 3],
st.to_string_double,
rustyFloatToStr,
)

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

@ -1,142 +0,0 @@
# frozen_string_literal: true
require 'test/unit'
require 'rondpoint'
include Test::Unit::Assertions
include Rondpoint
dico = Dictionnaire.new Enumeration::DEUX, true, 0, 123_456_789
assert_equal dico, Rondpoint.copie_dictionnaire(dico)
assert_equal Rondpoint.copie_enumeration(Enumeration::DEUX), Enumeration::DEUX
assert_equal Rondpoint.copie_enumerations([
Enumeration::UN,
Enumeration::DEUX
]), [Enumeration::UN, Enumeration::DEUX]
assert_equal Rondpoint.copie_carte({
'0' => EnumerationAvecDonnees::ZERO.new,
'1' => EnumerationAvecDonnees::UN.new(1),
'2' => EnumerationAvecDonnees::DEUX.new(2, 'deux')
}), {
'0' => EnumerationAvecDonnees::ZERO.new,
'1' => EnumerationAvecDonnees::UN.new(1),
'2' => EnumerationAvecDonnees::DEUX.new(2, 'deux')
}
assert Rondpoint.switcheroo(false)
assert_not_equal EnumerationAvecDonnees::ZERO.new, EnumerationAvecDonnees::UN.new(1)
assert_equal EnumerationAvecDonnees::UN.new(1), EnumerationAvecDonnees::UN.new(1)
assert_not_equal EnumerationAvecDonnees::UN.new(1), EnumerationAvecDonnees::UN.new(2)
# Test the roundtrip across the FFI.
# This shows that the values we send come back in exactly the same state as we sent them.
# i.e. it shows that lowering from ruby and lifting into rust is symmetrical with
# lowering from rust and lifting into ruby.
RT = Retourneur.new
def affirm_aller_retour(vals, fn_name)
vals.each do |v|
id_v = RT.public_send fn_name, v
assert_equal id_v, v, "Round-trip failure: #{v} => #{id_v}"
end
end
MIN_I8 = -1 * 2**7
MAX_I8 = 2**7 - 1
MIN_I16 = -1 * 2**15
MAX_I16 = 2**15 - 1
MIN_I32 = -1 * 2**31
MAX_I32 = 2**31 - 1
MIN_I64 = -1 * 2**31
MAX_I64 = 2**31 - 1
# Ruby floats are always doubles, so won't round-trip through f32 correctly.
# This truncates them appropriately.
F32_ONE_THIRD = [1.0 / 3].pack('f').unpack('f')[0]
# Booleans
affirm_aller_retour([true, false], :identique_boolean)
# Bytes.
affirm_aller_retour([MIN_I8, -1, 0, 1, MAX_I8], :identique_i8)
affirm_aller_retour([0x00, 0x12, 0xFF], :identique_u8)
# Shorts
affirm_aller_retour([MIN_I16, -1, 0, 1, MAX_I16], :identique_i16)
affirm_aller_retour([0x0000, 0x1234, 0xFFFF], :identique_u16)
# Ints
affirm_aller_retour([MIN_I32, -1, 0, 1, MAX_I32], :identique_i32)
affirm_aller_retour([0x00000000, 0x12345678, 0xFFFFFFFF], :identique_u32)
# Longs
affirm_aller_retour([MIN_I64, -1, 0, 1, MAX_I64], :identique_i64)
affirm_aller_retour([0x0000000000000000, 0x1234567890ABCDEF, 0xFFFFFFFFFFFFFFFF], :identique_u64)
# Floats
affirm_aller_retour([0.0, 0.5, 0.25, 1.0, F32_ONE_THIRD], :identique_float)
# Doubles
affirm_aller_retour(
[0.0, 0.5, 0.25, 1.0, 1.0 / 3, Float::MAX, Float::MIN],
:identique_double
)
# Strings
affirm_aller_retour(
['', 'abc', 'été', 'ښي لاس ته لوستلو لوستل',
'😻emoji 👨👧👦multi-emoji, 🇨🇭a flag, a canal, panama'],
:identique_string
)
# Test one way across the FFI.
#
# We send one representation of a value to lib.rs, and it transforms it into another, a string.
# lib.rs sends the string back, and then we compare here in ruby.
#
# This shows that the values are transformed into strings the same way in both ruby and rust.
# i.e. if we assume that the string return works (we test this assumption elsewhere)
# we show that lowering from ruby and lifting into rust has values that both ruby and rust
# both stringify in the same way. i.e. the same values.
#
# If we roundtripping proves the symmetry of our lowering/lifting from here to rust, and lowering/lifting from rust to here,
# and this convinces us that lowering/lifting from here to rust is correct, then
# together, we've shown the correctness of the return leg.
ST = Stringifier.new
def affirm_enchaine(vals, fn_name)
vals.each do |v|
str_v = ST.public_send fn_name, v
assert_equal v.to_s, str_v, "String compare error #{v} => #{str_v}"
end
end
# Test the efficacy of the string transport from rust. If this fails, but everything else
# works, then things are very weird.
assert_equal ST.well_known_string('ruby'), 'uniffi 💚 ruby!'
# Booleans
affirm_enchaine([true, false], :to_string_boolean)
# Bytes.
affirm_enchaine([MIN_I8, -1, 0, 1, MAX_I8], :to_string_i8)
affirm_enchaine([0x00, 0x12, 0xFF], :to_string_u8)
# Shorts
affirm_enchaine([MIN_I16, -1, 0, 1, MAX_I16], :to_string_i16)
affirm_enchaine([0x0000, 0x1234, 0xFFFF], :to_string_u16)
# Ints
affirm_enchaine([MIN_I32, -1, 0, 1, MAX_I32], :to_string_i32)
affirm_enchaine([0x00000000, 0x12345678, 0xFFFFFFFF], :to_string_u32)
# Longs
affirm_enchaine([MIN_I64, -1, 0, 1, MAX_I64], :to_string_i64)
affirm_enchaine([0x0000000000000000, 0x1234567890ABCDEF, 0xFFFFFFFFFFFFFFFF], :to_string_u64)

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

@ -1,232 +0,0 @@
import rondpoint
let dico = Dictionnaire(un: .deux, deux: false, petitNombre: 0, grosNombre: 123456789)
let copyDico = copieDictionnaire(d: dico)
assert(dico == copyDico)
assert(copieEnumeration(e: .deux) == .deux)
assert(copieEnumerations(e: [.un, .deux]) == [.un, .deux])
assert(copieCarte(c:
["0": .zero,
"1": .un(premier: 1),
"2": .deux(premier: 2, second: "deux")
]) == [
"0": .zero,
"1": .un(premier: 1),
"2": .deux(premier: 2, second: "deux")
])
assert(EnumerationAvecDonnees.zero != EnumerationAvecDonnees.un(premier: 1))
assert(EnumerationAvecDonnees.un(premier: 1) == EnumerationAvecDonnees.un(premier: 1))
assert(EnumerationAvecDonnees.un(premier: 1) != EnumerationAvecDonnees.un(premier: 2))
assert(switcheroo(b: false))
// Test the roundtrip across the FFI.
// This shows that the values we send come back in exactly the same state as we sent them.
// i.e. it shows that lowering from swift and lifting into rust is symmetrical with
// lowering from rust and lifting into swift.
let rt = Retourneur()
// Booleans
[true, false].affirmAllerRetour(rt.identiqueBoolean)
// Bytes.
[.min, .max].affirmAllerRetour(rt.identiqueI8)
[0x00, 0xFF].map { $0 as UInt8 }.affirmAllerRetour(rt.identiqueU8)
// Shorts
[.min, .max].affirmAllerRetour(rt.identiqueI16)
[0x0000, 0xFFFF].map { $0 as UInt16 }.affirmAllerRetour(rt.identiqueU16)
// Ints
[0, 1, -1, .min, .max].affirmAllerRetour(rt.identiqueI32)
[0x00000000, 0xFFFFFFFF].map { $0 as UInt32 }.affirmAllerRetour(rt.identiqueU32)
// Longs
[.zero, 1, -1, .min, .max].affirmAllerRetour(rt.identiqueI64)
[.zero, 1, .min, .max].affirmAllerRetour(rt.identiqueU64)
// Floats
[.zero, 1, 0.25, .leastNonzeroMagnitude, .greatestFiniteMagnitude].affirmAllerRetour(rt.identiqueFloat)
// Doubles
[0.0, 1.0, .leastNonzeroMagnitude, .greatestFiniteMagnitude].affirmAllerRetour(rt.identiqueDouble)
// Strings
["", "abc", "null\0byte", "été", "ښي لاس ته لوستلو لوستل", "😻emoji 👨👧👦multi-emoji, 🇨🇭a flag, a canal, panama"]
.affirmAllerRetour(rt.identiqueString)
// Test one way across the FFI.
//
// We send one representation of a value to lib.rs, and it transforms it into another, a string.
// lib.rs sends the string back, and then we compare here in swift.
//
// This shows that the values are transformed into strings the same way in both swift and rust.
// i.e. if we assume that the string return works (we test this assumption elsewhere)
// we show that lowering from swift and lifting into rust has values that both swift and rust
// both stringify in the same way. i.e. the same values.
//
// If we roundtripping proves the symmetry of our lowering/lifting from here to rust, and lowering/lifting from rust t here,
// and this convinces us that lowering/lifting from here to rust is correct, then
// together, we've shown the correctness of the return leg.
let st = Stringifier()
// Test the effigacy of the string transport from rust. If this fails, but everything else
// works, then things are very weird.
let wellKnown = st.wellKnownString(value: "swift")
assert("uniffi 💚 swift!" == wellKnown, "wellKnownString 'uniffi 💚 swift!' == '\(wellKnown)'")
// Booleans
[true, false].affirmEnchaine(st.toStringBoolean)
// Bytes.
[.min, .max].affirmEnchaine(st.toStringI8)
[.min, .max].affirmEnchaine(st.toStringU8)
// Shorts
[.min, .max].affirmEnchaine(st.toStringI16)
[.min, .max].affirmEnchaine(st.toStringU16)
// Ints
[0, 1, -1, .min, .max].affirmEnchaine(st.toStringI32)
[0, 1, .min, .max].affirmEnchaine(st.toStringU32)
// Longs
[.zero, 1, -1, .min, .max].affirmEnchaine(st.toStringI64)
[.zero, 1, .min, .max].affirmEnchaine(st.toStringU64)
// Floats
[.zero, 1, -1, .leastNonzeroMagnitude, .greatestFiniteMagnitude].affirmEnchaine(st.toStringFloat) { Float.init($0) == $1 }
// Doubles
[.zero, 1, -1, .leastNonzeroMagnitude, .greatestFiniteMagnitude].affirmEnchaine(st.toStringDouble) { Double.init($0) == $1 }
// Some extension functions for testing the results of roundtripping and stringifying
extension Array where Element: Equatable {
static func defaultEquals(_ observed: String, expected: Element) -> Bool {
let exp = "\(expected)"
return observed == exp
}
func affirmEnchaine(_ fn: (Element) -> String, equals: (String, Element) -> Bool = defaultEquals) {
self.forEach { v in
let obs = fn(v)
assert(equals(obs, v), "toString_\(type(of:v))(\(v)): observed=\(obs), expected=\(v)")
}
}
func affirmAllerRetour(_ fn: (Element) -> Element) {
self.forEach { v in
assert(fn(v) == v, "identique_\(type(of:v))(\(v))")
}
}
}
// Prove to ourselves that default arguments are being used.
// Step 1: call the methods without arguments, and check against the UDL.
let op = Optionneur()
assert(op.sinonString() == "default")
assert(op.sinonBoolean() == false)
assert(op.sinonSequence() == [])
// optionals
assert(op.sinonNull() == nil)
assert(op.sinonZero() == 0)
// decimal integers
assert(op.sinonU8Dec() == UInt8(42))
assert(op.sinonI8Dec() == Int8(-42))
assert(op.sinonU16Dec() == UInt16(42))
assert(op.sinonI16Dec() == Int16(42))
assert(op.sinonU32Dec() == UInt32(42))
assert(op.sinonI32Dec() == Int32(42))
assert(op.sinonU64Dec() == UInt64(42))
assert(op.sinonI64Dec() == Int64(42))
// hexadecimal integers
assert(op.sinonU8Hex() == UInt8(0xff))
assert(op.sinonI8Hex() == Int8(-0x7f))
assert(op.sinonU16Hex() == UInt16(0xffff))
assert(op.sinonI16Hex() == Int16(0x7f))
assert(op.sinonU32Hex() == UInt32(0xffffffff))
assert(op.sinonI32Hex() == Int32(0x7fffffff))
assert(op.sinonU64Hex() == UInt64(0xffffffffffffffff))
assert(op.sinonI64Hex() == Int64(0x7fffffffffffffff))
// octal integers
assert(op.sinonU32Oct() == UInt32(0o755))
// floats
assert(op.sinonF32() == 42.0)
assert(op.sinonF64() == Double(42.1))
// enums
assert(op.sinonEnum() == .trois)
// Step 2. Convince ourselves that if we pass something else, then that changes the output.
// We have shown something coming out of the sinon methods, but without eyeballing the Rust
// we can't be sure that the arguments will change the return value.
["foo", "bar"].affirmAllerRetour(op.sinonString)
[true, false].affirmAllerRetour(op.sinonBoolean)
[["a", "b"], []].affirmAllerRetour(op.sinonSequence)
// optionals
["0", "1"].affirmAllerRetour(op.sinonNull)
[0, 1].affirmAllerRetour(op.sinonZero)
// integers
[0, 1].affirmAllerRetour(op.sinonU8Dec)
[0, 1].affirmAllerRetour(op.sinonI8Dec)
[0, 1].affirmAllerRetour(op.sinonU16Dec)
[0, 1].affirmAllerRetour(op.sinonI16Dec)
[0, 1].affirmAllerRetour(op.sinonU32Dec)
[0, 1].affirmAllerRetour(op.sinonI32Dec)
[0, 1].affirmAllerRetour(op.sinonU64Dec)
[0, 1].affirmAllerRetour(op.sinonI64Dec)
[0, 1].affirmAllerRetour(op.sinonU8Hex)
[0, 1].affirmAllerRetour(op.sinonI8Hex)
[0, 1].affirmAllerRetour(op.sinonU16Hex)
[0, 1].affirmAllerRetour(op.sinonI16Hex)
[0, 1].affirmAllerRetour(op.sinonU32Hex)
[0, 1].affirmAllerRetour(op.sinonI32Hex)
[0, 1].affirmAllerRetour(op.sinonU64Hex)
[0, 1].affirmAllerRetour(op.sinonI64Hex)
[0, 1].affirmAllerRetour(op.sinonU32Oct)
// floats
[0.0, 1.0].affirmAllerRetour(op.sinonF32)
[0.0, 1.0].affirmAllerRetour(op.sinonF64)
// enums
[.un, .deux, .trois].affirmAllerRetour(op.sinonEnum)
// Testing defaulting properties in record types.
let defaultes = OptionneurDictionnaire()
let explicite = OptionneurDictionnaire(
i8Var: Int8(-8),
u8Var: UInt8(8),
i16Var: Int16(-16),
u16Var: UInt16(0x10),
i32Var: -32,
u32Var: UInt32(32),
i64Var: Int64(-64),
u64Var: UInt64(64),
floatVar: Float(4.0),
doubleVar: Double(8.0),
booleanVar: true,
stringVar: "default",
listVar: [],
enumerationVar: .deux,
dictionnaireVar: nil
)
// and makes sure they travel across and back the FFI.
assert(defaultes == explicite)
[defaultes].affirmAllerRetour(rt.identiqueOptionneurDictionnaire)

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

@ -1,9 +0,0 @@
uniffi_macros::build_foreign_language_testcases!(
["src/rondpoint.udl",],
[
"tests/bindings/test_rondpoint.kts",
"tests/bindings/test_rondpoint.swift",
"tests/bindings/test_rondpoint.py",
"tests/bindings/test_rondpoint.rb",
]
);

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

@ -1 +0,0 @@
{"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}

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

@ -1,18 +0,0 @@
[package]
name = "uniffi-example-sprites"
edition = "2021"
version = "0.18.0"
authors = ["Firefox Sync Team <sync-team@mozilla.com>"]
license = "MPL-2.0"
publish = false
[lib]
crate-type = ["lib", "cdylib"]
name = "uniffi_sprites"
[dependencies]
uniffi_macros = {path = "../../uniffi_macros"}
uniffi = {path = "../../uniffi", features=["builtin-bindgen"]}
[build-dependencies]
uniffi_build = {path = "../../uniffi_build", features=["builtin-bindgen"]}

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

@ -1,7 +0,0 @@
/* 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/sprites.udl").unwrap();
}

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

@ -1,65 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::sync::RwLock;
// A point in two-dimensional space.
#[derive(Debug, Clone)]
pub struct Point {
x: f64,
y: f64,
}
// A magnitude and direction in two-dimensional space.
// For simplicity we represent this as a point relative to the origin.
#[derive(Debug, Clone)]
pub struct Vector {
dx: f64,
dy: f64,
}
// Move from the given Point, according to the given Vector.
pub fn translate(p: &Point, v: Vector) -> Point {
Point {
x: p.x + v.dx,
y: p.y + v.dy,
}
}
// An entity in our imaginary world, which occupies a position in space
// and which can move about over time.
#[derive(Debug)]
pub struct Sprite {
// We must use interior mutability for managing mutable state, hence the `RwLock`.
current_position: RwLock<Point>,
}
impl Sprite {
fn new(initial_position: Option<Point>) -> Sprite {
Sprite {
current_position: RwLock::new(initial_position.unwrap_or(Point { x: 0.0, y: 0.0 })),
}
}
fn new_relative_to(reference: Point, direction: Vector) -> Sprite {
Sprite {
current_position: RwLock::new(translate(&reference, direction)),
}
}
fn get_position(&self) -> Point {
self.current_position.read().unwrap().clone()
}
fn move_to(&self, position: Point) {
*self.current_position.write().unwrap() = position;
}
fn move_by(&self, direction: Vector) {
let mut current_position = self.current_position.write().unwrap();
*current_position = translate(&*current_position, direction)
}
}
include!(concat!(env!("OUT_DIR"), "/sprites.uniffi.rs"));

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

@ -1,22 +0,0 @@
namespace sprites {
Point translate([ByRef] Point position, Vector direction);
};
dictionary Point {
double x;
double y;
};
dictionary Vector {
double dx;
double dy;
};
interface Sprite {
constructor(Point? initial_position);
[Name=new_relative_to] constructor(Point reference, Vector direction);
Point get_position();
void move_to(Point position);
void move_by(Vector direction);
};

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

@ -1,25 +0,0 @@
import uniffi.sprites.*;
val sempty = Sprite(null)
assert( sempty.getPosition() == Point(0.0, 0.0) )
val s = Sprite(Point(0.0, 1.0))
assert( s.getPosition() == Point(0.0, 1.0) )
s.moveTo(Point(1.0, 2.0))
assert( s.getPosition() == Point(1.0, 2.0) )
s.moveBy(Vector(-4.0, 2.0))
assert( s.getPosition() == Point(-3.0, 4.0) )
s.destroy()
try {
s.moveBy(Vector(0.0, 0.0))
assert(false) { "Should not be able to call anything after `destroy`" }
} catch(e: IllegalStateException) {
assert(true)
}
val srel = Sprite.newRelativeTo(Point(0.0, 1.0), Vector(1.0, 1.5))
assert( srel.getPosition() == Point(1.0, 2.5) )

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

@ -1,17 +0,0 @@
from sprites import *
sempty = Sprite(None)
assert sempty.get_position() == Point(0, 0)
s = Sprite(Point(0, 1))
assert s.get_position() == Point(0, 1)
s.move_to(Point(1, 2))
assert s.get_position() == Point(1, 2)
s.move_by(Vector(-4, 2))
assert s.get_position() == Point(-3, 4)
srel = Sprite.new_relative_to(Point(0, 1), Vector(1, 1.5))
assert srel.get_position() == Point(1, 2.5)

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

@ -1,22 +0,0 @@
# frozen_string_literal: true
require 'test/unit'
require 'sprites'
include Test::Unit::Assertions
include Sprites
sempty = Sprite.new(nil)
assert_equal sempty.get_position, Point.new(0, 0)
s = Sprite.new(Point.new(0, 1))
assert_equal s.get_position, Point.new(0, 1)
s.move_to(Point.new(1, 2))
assert_equal s.get_position, Point.new(1, 2)
s.move_by(Vector.new(-4, 2))
assert_equal s.get_position, Point.new(-3, 4)
srel = Sprite.new_relative_to(Point.new(0, 1), Vector.new(1, 1.5))
assert_equal srel.get_position, Point.new(1, 2.5)

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

@ -1,16 +0,0 @@
import sprites
let sempty = Sprite(initialPosition: nil)
assert( sempty.getPosition() == Point(x: 0, y: 0))
let s = Sprite(initialPosition: Point(x: 0, y: 1))
assert( s.getPosition() == Point(x: 0, y: 1))
s.moveTo(position: Point(x: 1.0, y: 2.0))
assert( s.getPosition() == Point(x: 1, y: 2))
s.moveBy(direction: Vector(dx: -4, dy: 2))
assert( s.getPosition() == Point(x: -3, y: 4))
let srel = Sprite.newRelativeTo(reference: Point(x: 0.0, y: 1.0), direction: Vector(dx: 1, dy: 1.5))
assert( srel.getPosition() == Point(x: 1.0, y: 2.5) )

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

@ -1,9 +0,0 @@
uniffi_macros::build_foreign_language_testcases!(
["src/sprites.udl",],
[
"tests/bindings/test_sprites.py",
"tests/bindings/test_sprites.rb",
"tests/bindings/test_sprites.kts",
"tests/bindings/test_sprites.swift",
]
);

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

@ -1 +0,0 @@
{"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}

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

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

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

@ -1,7 +0,0 @@
/* 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/todolist.udl").unwrap();
}

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

@ -1,150 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::sync::{Arc, RwLock};
#[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);
}
#[derive(Debug, thiserror::Error)]
pub enum TodoError {
#[error("The todo does not exist!")]
TodoDoesNotExist,
#[error("The todolist is empty!")]
EmptyTodoList,
#[error("That todo already exists!")]
DuplicateTodo,
#[error("Empty String error!: {0}")]
EmptyString(String),
#[error("I am a delegated Error: {0}")]
DeligatedError(#[from] std::io::Error),
}
/// Get a reference to the global default TodoList, if set.
///
fn get_default_list() -> Option<Arc<TodoList>> {
DEFAULT_LIST.read().unwrap().clone()
}
/// Set the global default TodoList.
///
/// This will silently drop any previously set value.
///
fn set_default_list(list: Arc<TodoList>) {
*DEFAULT_LIST.write().unwrap() = Some(list);
}
/// Create a new TodoEntry from the given string.
///
fn create_entry_with<S: Into<String>>(item: S) -> Result<TodoEntry> {
let text = item.into();
if text.is_empty() {
return Err(TodoError::EmptyString(
"Cannot add empty string as entry".to_string(),
));
}
Ok(TodoEntry { text })
}
type Result<T, E = TodoError> = std::result::Result<T, E>;
// A simple Todolist.
// UniFFI requires that we use interior mutability for managing mutable state, so we wrap our `Vec` in a RwLock.
// (A Mutex would also work, but a RwLock is more appropriate for this use-case, so we use it).
#[derive(Debug)]
pub struct TodoList {
items: RwLock<Vec<String>>,
}
impl TodoList {
fn new() -> Self {
Self {
items: RwLock::new(Vec::new()),
}
}
fn add_item<S: Into<String>>(&self, item: S) -> Result<()> {
let item = item.into();
if item.is_empty() {
return Err(TodoError::EmptyString(
"Cannot add empty string as item".to_string(),
));
}
let mut items = self.items.write().unwrap();
if items.contains(&item) {
return Err(TodoError::DuplicateTodo);
}
items.push(item);
Ok(())
}
fn get_last(&self) -> Result<String> {
let items = self.items.read().unwrap();
items.last().cloned().ok_or(TodoError::EmptyTodoList)
}
fn get_first(&self) -> Result<String> {
let items = self.items.read().unwrap();
items.first().cloned().ok_or(TodoError::EmptyTodoList)
}
fn add_entries(&self, entries: Vec<TodoEntry>) {
let mut items = self.items.write().unwrap();
items.extend(entries.into_iter().map(|e| e.text))
}
fn add_entry(&self, entry: TodoEntry) -> Result<()> {
self.add_item(entry.text)
}
fn add_items<S: Into<String>>(&self, items: Vec<S>) {
let mut my_items = self.items.write().unwrap();
my_items.extend(items.into_iter().map(Into::into))
}
fn get_items(&self) -> Vec<String> {
let items = self.items.read().unwrap();
items.clone()
}
fn get_entries(&self) -> Vec<TodoEntry> {
let items = self.items.read().unwrap();
items
.iter()
.map(|text| TodoEntry { text: text.clone() })
.collect()
}
fn get_last_entry(&self) -> Result<TodoEntry> {
let text = self.get_last()?;
Ok(TodoEntry { text })
}
fn clear_item<S: Into<String>>(&self, item: S) -> Result<()> {
let item = item.into();
let mut items = self.items.write().unwrap();
let idx = items
.iter()
.position(|s| s == &item)
.ok_or(TodoError::TodoDoesNotExist)?;
items.remove(idx);
Ok(())
}
fn make_default(self: Arc<Self>) {
set_default_list(self);
}
}
include!(concat!(env!("OUT_DIR"), "/todolist.uniffi.rs"));

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

@ -1,38 +0,0 @@
namespace todolist {
TodoList? get_default_list();
undefined set_default_list(TodoList list);
[Throws=TodoError]
TodoEntry create_entry_with(string todo);
};
dictionary TodoEntry {
string text;
};
[Error]
enum TodoError {
"TodoDoesNotExist", "EmptyTodoList", "DuplicateTodo", "EmptyString", "DeligatedError"
};
interface TodoList {
constructor();
[Throws=TodoError]
void add_item(string todo);
[Throws=TodoError]
void add_entry(TodoEntry entry);
sequence<TodoEntry> get_entries();
sequence<string> get_items();
void add_entries(sequence<TodoEntry> entries);
void add_items(sequence<string> items);
[Throws=TodoError]
TodoEntry get_last_entry();
[Throws=TodoError]
string get_last();
[Throws=TodoError]
string get_first();
[Throws=TodoError]
void clear_item(string todo);
[Self=ByArc]
undefined make_default();
};

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

@ -1,83 +0,0 @@
import uniffi.todolist.*
val todo = TodoList()
// This throws an exception:
try {
todo.getLast()
throw RuntimeException("Should have thrown a TodoError!")
} catch (e: TodoException.EmptyTodoList) {
// It's okay, we don't have any items yet!
}
try {
createEntryWith("")
throw RuntimeException("Should have thrown a TodoError!")
} catch (e: TodoException) {
// It's okay, the string was empty!
assert(e is TodoException.EmptyString)
assert(e !is TodoException.EmptyTodoList)
}
todo.addItem("Write strings support")
assert(todo.getLast() == "Write strings support")
todo.addItem("Write tests for strings support")
assert(todo.getLast() == "Write tests for strings support")
val entry = createEntryWith("Write bindings for strings as record members")
todo.addEntry(entry)
assert(todo.getLast() == "Write bindings for strings as record members")
assert(todo.getLastEntry().text == "Write bindings for strings as record members")
todo.addItem("Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣")
assert(todo.getLast() == "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣")
val entry2 = TodoEntry("Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣")
todo.addEntry(entry2)
assert(todo.getLastEntry().text == "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣")
assert(todo.getEntries().size == 5)
todo.addEntries(listOf(TodoEntry("foo"), TodoEntry("bar")))
assert(todo.getEntries().size == 7)
assert(todo.getLastEntry().text == "bar")
todo.addItems(listOf("bobo", "fofo"))
assert(todo.getItems().size == 9)
assert(todo.getItems()[7] == "bobo")
assert(getDefaultList() == null)
// Note that each individual object instance needs to be explicitly destroyed,
// either by using the `.use` helper or explicitly calling its `.destroy` method.
// Failure to do so will leak the underlying Rust object.
TodoList().use { todo2 ->
setDefaultList(todo)
getDefaultList()!!.use { default ->
assert(todo.getEntries() == default.getEntries())
assert(todo2.getEntries() != default.getEntries())
}
todo2.makeDefault()
getDefaultList()!!.use { default ->
assert(todo.getEntries() != default.getEntries())
assert(todo2.getEntries() == default.getEntries())
}
todo.addItem("Test liveness after being demoted from default")
assert(todo.getLast() == "Test liveness after being demoted from default")
todo2.addItem("Test shared state through local vs default reference")
getDefaultList()!!.use { default ->
assert(default.getLast() == "Test shared state through local vs default reference")
}
}
// Ensure the kotlin version of deinit doesn't crash, and is idempotent.
todo.destroy()
todo.destroy()

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

@ -1,44 +0,0 @@
from todolist import *
todo = TodoList()
entry = TodoEntry("Write bindings for strings in records")
todo.add_item("Write python bindings")
assert(todo.get_last() == "Write python bindings")
todo.add_item("Write tests for bindings")
assert(todo.get_last() == "Write tests for bindings")
todo.add_entry(entry)
assert(todo.get_last() == "Write bindings for strings in records")
assert(todo.get_last_entry().text == "Write bindings for strings in records")
todo.add_item("Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣")
assert(todo.get_last() == "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣")
entry2 = TodoEntry("Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣")
todo.add_entry(entry2)
assert(todo.get_last_entry().text == "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣")
todo2 = TodoList()
assert(todo != todo2)
assert(todo is not todo2)
assert(get_default_list() is None)
set_default_list(todo)
assert(todo.get_items() == get_default_list().get_items())
todo2.make_default()
assert(todo2.get_items() == get_default_list().get_items())
todo.add_item("Test liveness after being demoted from default")
assert(todo.get_last() == "Test liveness after being demoted from default")
todo2.add_item("Test shared state through local vs default reference")
assert(get_default_list().get_last() == "Test shared state through local vs default reference")

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

@ -1,47 +0,0 @@
# frozen_string_literal: true
require 'test/unit'
require 'todolist'
include Test::Unit::Assertions
include Todolist
todo = TodoList.new
entry = TodoEntry.new 'Write bindings for strings in records'
todo.add_item('Write ruby bindings')
assert_equal todo.get_last, 'Write ruby bindings'
todo.add_item('Write tests for bindings')
assert_equal todo.get_last, 'Write tests for bindings'
todo.add_entry(entry)
assert_equal todo.get_last, 'Write bindings for strings in records'
assert_equal todo.get_last_entry.text, 'Write bindings for strings in records'
todo.add_item("Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣")
assert_equal todo.get_last, "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣"
entry2 = TodoEntry.new("Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣")
todo.add_entry(entry2)
assert_equal todo.get_last_entry.text, "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣"
todo2 = TodoList.new
assert todo2.get_items != todo.get_items
assert Todolist.get_default_list == nil
Todolist.set_default_list todo
assert todo.get_items == Todolist.get_default_list.get_items
todo2.make_default
assert todo2.get_items == Todolist.get_default_list.get_items
todo.add_item "Test liveness after being demoted from default"
assert todo.get_last == "Test liveness after being demoted from default"
todo2.add_item "Test shared state through local vs default reference"
assert Todolist.get_default_list.get_last == "Test shared state through local vs default reference"

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

@ -1,69 +0,0 @@
import todolist
let todo = TodoList()
do {
let _ = try todo.getLast()
fatalError("Should have thrown an EmptyTodoList error!")
} catch TodoError.EmptyTodoList{
//It's okay! There are not todos!
}
try! todo.addItem(todo: "Write swift bindings")
assert( try! todo.getLast() == "Write swift bindings")
try! todo.addItem(todo: "Write tests for bindings")
assert(try! todo.getLast() == "Write tests for bindings")
let entry = TodoEntry(text: "Write bindings for strings as record members")
try! todo.addEntry(entry: entry)
assert(try! todo.getLast() == "Write bindings for strings as record members")
try! todo.addItem(todo: "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣")
assert(try! todo.getLast() == "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣")
do {
let _ = try createEntryWith(todo: "")
fatalError("Should have thrown an EmptyString error!")
} catch TodoError.EmptyString {
// It's okay! It was an empty string
}
let entry2 = TodoEntry(text: "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣")
try! todo.addEntry(entry: entry2)
assert(try! todo.getLastEntry() == entry2)
assert(todo.getEntries().count == 5)
todo.addEntries(entries: [TodoEntry(text: "foo"), TodoEntry(text: "bar")])
assert(todo.getEntries().count == 7)
assert(todo.getItems().count == 7)
assert(try! todo.getLast() == "bar")
todo.addItems(items: ["bobo", "fofo"])
assert(todo.getItems().count == 9)
assert(todo.getItems()[7] == "bobo")
// Ensure deinit doesn't crash.
for _ in 0..<10 {
let list = TodoList()
try! list.addItem(todo: "todo")
}
let todo2 = TodoList()
assert(getDefaultList() == nil)
setDefaultList(list: todo)
assert(todo.getItems() == getDefaultList()!.getItems())
assert(todo2.getItems() != getDefaultList()!.getItems())
todo2.makeDefault()
assert(todo.getItems() != getDefaultList()!.getItems())
assert(todo2.getItems() == getDefaultList()!.getItems())
try! todo.addItem(todo: "Test liveness after being demoted from default")
assert(try! todo.getLast() == "Test liveness after being demoted from default")
try! todo2.addItem(todo: "Test shared state through local vs default reference")
assert(try! getDefaultList()!.getLast() == "Test shared state through local vs default reference")

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

@ -1,9 +0,0 @@
uniffi_macros::build_foreign_language_testcases!(
["src/todolist.udl",],
[
"tests/bindings/test_todolist.kts",
"tests/bindings/test_todolist.swift",
"tests/bindings/test_todolist.rb",
"tests/bindings/test_todolist.py"
]
);

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

@ -75,7 +75,6 @@ DIRS += [
"timermanager",
"tooltiptext",
"typeaheadfind",
"uniffi-js",
"utils",
"url-classifier",
"urlformatter",

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

@ -1,19 +0,0 @@
[package]
name = "uniffi-bindgen-gecko-js"
version = "0.1.0"
edition = "2018"
[[bin]]
name = "uniffi-bindgen-gecko-js"
path = "src/main.rs"
[dependencies]
anyhow = "1"
askama = { version = "0.11", default-features = false, features = ["config"] }
clap = { version = "3.1", features = ["std", "derive"] }
extend = "1.1"
heck = "0.4"
uniffi_bindgen = "0.19"
serde = "1"
toml = "0.5"
camino = "1.0.8"

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

@ -1,2 +0,0 @@
[general]
dirs = ["src/templates"]

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

@ -1,139 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Manage the universe of ComponentInterfaces
//!
//! uniffi-bindgen-gecko-js is unique because it generates bindings over a set of UDL files rather
//! than just one. This is because we want to generate the WebIDL statically rather than generate
//! it. To accomplish that, each WebIDL function inputs an opaque integer id that identifies which
//! version of it should run, for example `CallSync` inputs a function id. Operating on all UDL
//! files at once simplifies the task of ensuring those ids are to be unique and consistent between
//! the JS and c++ code.
//!
//! This module manages the list of ComponentInterface and the object ids.
use crate::render::cpp::ComponentInterfaceCppExt;
use anyhow::{bail, Context, Result};
use camino::Utf8PathBuf;
use std::collections::{BTreeSet, HashMap, HashSet};
use uniffi_bindgen::interface::{ComponentInterface, FFIFunction, Object};
pub struct ComponentInterfaceUniverse {
ci_list: Vec<ComponentInterface>,
fixture_ci_list: Vec<ComponentInterface>,
}
impl ComponentInterfaceUniverse {
pub fn new(udl_files: Vec<Utf8PathBuf>, fixture_udl_files: Vec<Utf8PathBuf>) -> Result<Self> {
let ci_list = udl_files
.into_iter()
.map(parse_udl_file)
.collect::<Result<Vec<_>>>()?;
let fixture_ci_list = fixture_udl_files
.into_iter()
.map(parse_udl_file)
.collect::<Result<Vec<_>>>()?;
Self::check_udl_namespaces_unique(&ci_list, &fixture_ci_list)?;
Ok(Self {
ci_list,
fixture_ci_list,
})
}
fn check_udl_namespaces_unique(
ci_list: &Vec<ComponentInterface>,
fixture_ci_list: &Vec<ComponentInterface>,
) -> Result<()> {
let mut set = HashSet::new();
for ci in ci_list.iter().chain(fixture_ci_list.iter()) {
if !set.insert(ci.namespace()) {
bail!("UDL files have duplicate namespace: {}", ci.namespace());
}
}
Ok(())
}
pub fn ci_list(&self) -> &Vec<ComponentInterface> {
&self.ci_list
}
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())
}
}
fn parse_udl_file(udl_file: Utf8PathBuf) -> Result<ComponentInterface> {
let udl = std::fs::read_to_string(&udl_file).context("Error reading UDL file")?;
ComponentInterface::from_webidl(&udl).context("Failed to parse UDL")
}
pub struct FunctionIds<'a> {
// Map (CI namespace, func name) -> Ids
map: HashMap<(&'a str, &'a str), usize>,
}
impl<'a> FunctionIds<'a> {
pub fn new(cis: &'a ComponentInterfaceUniverse) -> Self {
Self {
map: cis
.iter_all()
.flat_map(|ci| {
ci.exposed_functions()
.into_iter()
.map(move |f| (ci.namespace(), f.name()))
})
.enumerate()
.map(|(i, (namespace, name))| ((namespace, name), i))
// Sort using BTreeSet to guarantee the IDs remain stable across runs
.collect::<BTreeSet<_>>()
.into_iter()
.collect(),
}
}
pub fn get(&self, ci: &ComponentInterface, func: &FFIFunction) -> usize {
return *self.map.get(&(ci.namespace(), func.name())).unwrap();
}
pub fn name(&self, ci: &ComponentInterface, func: &FFIFunction) -> String {
format!("{}:{}", ci.namespace(), func.name())
}
}
pub struct ObjectIds<'a> {
// Map (CI namespace, object name) -> Ids
map: HashMap<(&'a str, &'a str), usize>,
}
impl<'a> ObjectIds<'a> {
pub fn new(cis: &'a ComponentInterfaceUniverse) -> Self {
Self {
map: cis
.iter_all()
.flat_map(|ci| {
ci.object_definitions()
.iter()
.map(move |o| (ci.namespace(), o.name()))
})
.enumerate()
.map(|(i, (namespace, name))| ((namespace, name), i))
// Sort using BTreeSet to guarantee the IDs remain stable across runs
.collect::<BTreeSet<_>>()
.into_iter()
.collect(),
}
}
pub fn get(&self, ci: &ComponentInterface, obj: &Object) -> usize {
return *self.map.get(&(ci.namespace(), obj.name())).unwrap();
}
pub fn name(&self, ci: &ComponentInterface, obj: &Object) -> String {
format!("{}:{}", ci.namespace(), obj.name())
}
}

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

@ -1,123 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use anyhow::{Context, Result};
use askama::Template;
use camino::Utf8PathBuf;
use clap::Parser;
use heck::ToTitleCase;
use std::fs::File;
use std::io::Write;
mod ci_list;
mod render;
pub use ci_list::{ComponentInterfaceUniverse, FunctionIds, ObjectIds};
pub use render::cpp::CPPScaffoldingTemplate;
pub use render::js::JSBindingsTemplate;
use uniffi_bindgen::ComponentInterface;
#[derive(Debug, Parser)]
#[clap(name = "uniffi-bindgen-gecko-js")]
#[clap(version = clap::crate_version!())]
#[clap(about = "JS bindings generator for Rust")]
#[clap(propagate_version = true)]
struct CliArgs {
// This is a really convoluted set of arguments, but we're only expecting to be called by
// `mach_commands.py`
#[clap(long, value_name = "FILE")]
js_dir: Utf8PathBuf,
#[clap(long, value_name = "FILE")]
fixture_js_dir: Utf8PathBuf,
#[clap(long, value_name = "FILE")]
cpp_path: Utf8PathBuf,
#[clap(long, value_name = "FILE")]
fixture_cpp_path: Utf8PathBuf,
#[clap(long, multiple_values = true, value_name = "FILES")]
udl_files: Vec<Utf8PathBuf>,
#[clap(long, multiple_values = true, value_name = "FILES")]
fixture_udl_files: Vec<Utf8PathBuf>,
}
fn render(out_path: Utf8PathBuf, template: impl Template) -> Result<()> {
println!("rendering {}", out_path);
let contents = template.render()?;
let mut f =
File::create(&out_path).context(format!("Failed to create {:?}", out_path.file_name()))?;
write!(f, "{}\n", contents).context(format!("Failed to write to {}", out_path))
}
fn render_cpp(
path: Utf8PathBuf,
prefix: &str,
ci_list: &Vec<ComponentInterface>,
function_ids: &FunctionIds,
object_ids: &ObjectIds,
) -> Result<()> {
render(
path,
CPPScaffoldingTemplate {
prefix,
ci_list,
function_ids: &function_ids,
object_ids: &object_ids,
},
)
}
fn render_js(
out_dir: Utf8PathBuf,
ci_list: &Vec<ComponentInterface>,
function_ids: &FunctionIds,
object_ids: &ObjectIds,
) -> Result<()> {
for ci in ci_list {
let path = out_dir.join(format!("{}.jsm", ci.namespace().to_title_case()));
render(
path,
JSBindingsTemplate {
ci,
function_ids: &function_ids,
object_ids: &object_ids,
},
)?;
}
Ok(())
}
pub fn run_main() -> Result<()> {
let args = CliArgs::parse();
let cis = ComponentInterfaceUniverse::new(args.udl_files, args.fixture_udl_files)?;
let function_ids = FunctionIds::new(&cis);
let object_ids = ObjectIds::new(&cis);
render_cpp(
args.cpp_path,
"UniFFI",
cis.ci_list(),
&function_ids,
&object_ids,
)?;
render_cpp(
args.fixture_cpp_path,
"UniFFIFixtures",
cis.fixture_ci_list(),
&function_ids,
&object_ids,
)?;
render_js(args.js_dir, cis.ci_list(), &function_ids, &object_ids)?;
render_js(
args.fixture_js_dir,
cis.fixture_ci_list(),
&function_ids,
&object_ids,
)?;
Ok(())
}

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

@ -1,9 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use anyhow::Result;
fn main() -> Result<()> {
uniffi_bindgen_gecko_js::run_main()
}

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

@ -1,154 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use crate::{FunctionIds, ObjectIds};
use askama::Template;
use extend::ext;
use heck::ToUpperCamelCase;
use std::collections::HashSet;
use std::iter;
use uniffi_bindgen::interface::{ComponentInterface, FFIArgument, FFIFunction, FFIType, Object};
#[derive(Template)]
#[template(path = "UniFFIScaffolding.cpp", escape = "none")]
pub struct CPPScaffoldingTemplate<'a> {
// Prefix for each function name in. This is related to how we handle the test fixtures. For
// each function defined in the UniFFI namespace in UniFFI.webidl we:
// - Generate a function in to handle it using the real UDL files
// - Generate a different function in for handle it using the fixture UDL files
// - Have a hand-written stub function that always calls the first function and only calls
// the second function in if MOZ_UNIFFI_FIXTURES is defined.
pub prefix: &'a str,
pub ci_list: &'a Vec<ComponentInterface>,
pub function_ids: &'a FunctionIds<'a>,
pub object_ids: &'a ObjectIds<'a>,
}
// Define extension traits with methods used in our template code
#[ext(name=ComponentInterfaceCppExt)]
pub impl ComponentInterface {
// C++ pointer type name. This needs to be a valid C++ type name and unique across all UDL
// files.
fn pointer_type(&self, object: &Object) -> String {
self._pointer_type(object.name())
}
fn _pointer_type(&self, name: &str) -> String {
format!(
"k{}{}PointerType",
self.namespace().to_upper_camel_case(),
name.to_upper_camel_case()
)
}
// Iterate over all functions to expose via the UniFFIScaffolding class
//
// This is basically all the user functions, except we don't expose the free methods for
// objects. Freeing is handled by the UniFFIPointer class.
//
// Note: this function should return `impl Iterator<&FFIFunction>`, but that's not currently
// allowed for traits.
fn exposed_functions(&self) -> Vec<&FFIFunction> {
let excluded: HashSet<_> = self
.object_definitions()
.iter()
.map(|o| o.ffi_object_free().name())
.collect();
self.iter_user_ffi_function_definitions()
.filter(move |f| !excluded.contains(f.name()))
.collect()
}
// ScaffoldingConverter class
//
// This is used to convert types between the JS code and Rust
fn scaffolding_converter(&self, ffi_type: &FFIType) -> String {
match ffi_type {
FFIType::RustArcPtr(name) => {
format!("ScaffoldingObjectConverter<&{}>", self._pointer_type(name),)
}
_ => format!("ScaffoldingConverter<{}>", ffi_type.rust_type()),
}
}
// ScaffoldingCallHandler class
fn scaffolding_call_handler(&self, func: &FFIFunction) -> String {
let return_param = match func.return_type() {
Some(return_type) => self.scaffolding_converter(return_type),
None => "ScaffoldingConverter<void>".to_string(),
};
let all_params = iter::once(return_param)
.chain(
func.arguments()
.into_iter()
.map(|a| self.scaffolding_converter(&a.type_())),
)
.collect::<Vec<_>>()
.join(", ");
return format!("ScaffoldingCallHandler<{}>", all_params);
}
}
#[ext(name=FFIFunctionCppExt)]
pub impl FFIFunction {
fn nm(&self) -> String {
self.name().to_upper_camel_case()
}
fn rust_name(&self) -> String {
self.name().to_string()
}
fn rust_return_type(&self) -> String {
match self.return_type() {
Some(t) => t.rust_type(),
None => "void".to_owned(),
}
}
fn rust_arg_list(&self) -> String {
let mut parts: Vec<String> = self.arguments().iter().map(|a| a.rust_type()).collect();
parts.push("RustCallStatus*".to_owned());
parts.join(", ")
}
}
#[ext(name=FFITypeCppExt)]
pub impl FFIType {
// Type for the Rust scaffolding code
fn rust_type(&self) -> String {
match self {
FFIType::UInt8 => "uint8_t",
FFIType::Int8 => "int8_t",
FFIType::UInt16 => "uint16_t",
FFIType::Int16 => "int16_t",
FFIType::UInt32 => "uint32_t",
FFIType::Int32 => "int32_t",
FFIType::UInt64 => "uint64_t",
FFIType::Int64 => "int64_t",
FFIType::Float32 => "float",
FFIType::Float64 => "double",
FFIType::RustBuffer => "RustBuffer",
FFIType::RustArcPtr(_) => "void *",
FFIType::ForeignBytes => unimplemented!("ForeignBytes not supported"),
FFIType::ForeignCallback => unimplemented!("ForeignCallback not supported"),
}
.to_owned()
}
}
#[ext(name=FFIArgumentCppExt)]
pub impl FFIArgument {
fn rust_type(&self) -> String {
self.type_().rust_type()
}
}
#[ext(name=ObjectCppExt)]
pub impl Object {
fn nm(&self) -> String {
self.name().to_upper_camel_case()
}
}

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

@ -1,232 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::shared::*;
use crate::{FunctionIds, ObjectIds};
use askama::Template;
use extend::ext;
use heck::{ToLowerCamelCase, ToShoutySnakeCase, ToUpperCamelCase};
use uniffi_bindgen::interface::{
Argument, ComponentInterface, Constructor, Enum, Error, Field, Function, Literal, Method,
Object, Radix, Record, Type,
};
fn arg_names(args: &[&Argument]) -> String {
args.iter()
.map(|arg| {
if let Some(default_value) = arg.default_value() {
format!("{} = {}", arg.nm(), default_value.render())
} else {
arg.nm()
}
})
.collect::<Vec<String>>()
.join(",")
}
fn render_enum_literal(typ: &Type, variant_name: &str) -> String {
if let Type::Enum(enum_name) = typ {
// TODO: This does not support complex enum literals yet.
return format!(
"{}.{}",
enum_name.to_upper_camel_case(),
variant_name.to_shouty_snake_case()
);
} else {
panic!("Rendering an enum literal on a type that is not an enum")
}
}
#[derive(Template)]
#[template(path = "js/wrapper.jsm", escape = "none")]
pub struct JSBindingsTemplate<'a> {
pub ci: &'a ComponentInterface,
pub function_ids: &'a FunctionIds<'a>,
pub object_ids: &'a ObjectIds<'a>,
}
// Define extension traits with methods used in our template code
#[ext(name=LiteralJSExt)]
pub impl Literal {
fn render(&self) -> String {
match self {
Literal::Boolean(inner) => inner.to_string(),
Literal::String(inner) => format!("\"{}\"", inner),
Literal::UInt(num, radix, _) => format!("{}", radix.render_num(num)),
Literal::Int(num, radix, _) => format!("{}", radix.render_num(num)),
Literal::Float(num, _) => num.clone(),
Literal::Enum(name, typ) => render_enum_literal(typ, name),
Literal::EmptyMap => "{}".to_string(),
Literal::EmptySequence => "[]".to_string(),
Literal::Null => "null".to_string(),
}
}
}
#[ext(name=RadixJSExt)]
pub impl Radix {
fn render_num(
&self,
num: impl std::fmt::Display + std::fmt::LowerHex + std::fmt::Octal,
) -> String {
match self {
Radix::Decimal => format!("{}", num),
Radix::Hexadecimal => format!("{:#x}", num),
Radix::Octal => format!("{:#o}", num),
}
}
}
#[ext(name=RecordJSExt)]
pub impl Record {
fn nm(&self) -> String {
self.name().to_upper_camel_case()
}
fn constructor_field_list(&self) -> String {
self.fields()
.iter()
.map(|field| {
if let Some(default_value) = field.default_value() {
format!("{} = {}", field.nm(), default_value.render())
} else {
field.nm()
}
})
.collect::<Vec<String>>()
.join(",")
}
}
#[ext(name=FieldJSExt)]
pub impl Field {
fn nm(&self) -> String {
self.name().to_lower_camel_case()
}
fn write_datastream_fn(&self) -> String {
self.type_().write_datastream_fn()
}
fn read_datastream_fn(&self) -> String {
self.type_().read_datastream_fn()
}
fn ffi_converter(&self) -> String {
self.type_().ffi_converter()
}
fn check_type(&self) -> String {
format!(
"{}.checkType(\"{}\", {})",
self.type_().ffi_converter(),
self.nm(),
self.nm()
)
}
}
#[ext(name=ArgumentJSExt)]
pub impl Argument {
fn lower_fn_name(&self) -> String {
format!("{}.lower", self.type_().ffi_converter())
}
fn nm(&self) -> String {
self.name().to_lower_camel_case()
}
fn check_type(&self) -> String {
format!(
"{}.checkType(\"{}\", {})",
self.type_().ffi_converter(),
self.nm(),
self.nm()
)
}
}
#[ext(name=TypeJSExt)]
pub impl Type {
// Render an expression to check if two instances of this type are equal
fn equals(&self, first: &str, second: &str) -> String {
match self {
Type::Record(_) => format!("{}.equals({})", first, second),
_ => format!("{} == {}", first, second),
}
}
fn write_datastream_fn(&self) -> String {
format!("{}.write", self.ffi_converter())
}
fn read_datastream_fn(&self) -> String {
format!("{}.read", self.ffi_converter())
}
fn ffi_converter(&self) -> String {
format!(
"FfiConverter{}",
self.canonical_name().to_upper_camel_case()
)
}
}
#[ext(name=EnumJSExt)]
pub impl Enum {
fn nm(&self) -> String {
self.name().to_upper_camel_case()
}
}
#[ext(name=FunctionJSExt)]
pub impl Function {
fn arg_names(&self) -> String {
arg_names(self.arguments().as_slice())
}
fn nm(&self) -> String {
self.name().to_lower_camel_case()
}
}
#[ext(name=ErrorJSExt)]
pub impl Error {
fn nm(&self) -> String {
self.name().to_upper_camel_case()
}
}
#[ext(name=ObjectJSExt)]
pub impl Object {
fn nm(&self) -> String {
self.name().to_upper_camel_case()
}
}
#[ext(name=ConstructorJSExt)]
pub impl Constructor {
fn nm(&self) -> String {
if self.is_primary_constructor() {
"init".to_string()
} else {
self.name().to_lower_camel_case()
}
}
fn arg_names(&self) -> String {
arg_names(&self.arguments().as_slice())
}
}
#[ext(name=MethodJSExt)]
pub impl Method {
fn arg_names(&self) -> String {
arg_names(self.arguments().as_slice())
}
fn nm(&self) -> String {
self.name().to_lower_camel_case()
}
}

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

@ -1,7 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
pub mod cpp;
pub mod js;
pub mod shared;

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

@ -1,39 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/// Extension traits that are shared across multiple render targets
use extend::ext;
use uniffi_bindgen::interface::{Constructor, FFIFunction, Function, Method};
#[ext]
pub impl FFIFunction {
fn is_async(&self) -> bool {
// TODO check `uniffi.toml` or some other configuration to figure this out
true
}
}
#[ext]
pub impl Function {
fn is_async(&self) -> bool {
// TODO check `uniffi.toml` or some other configuration to figure this out
true
}
}
#[ext]
pub impl Constructor {
fn is_async(&self) -> bool {
// TODO check `uniffi.toml` or some other configuration to figure this out
true
}
}
#[ext]
pub impl Method {
fn is_async(&self) -> bool {
// TODO check `uniffi.toml` or some other configuration to figure this out
true
}
}

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

@ -1,105 +0,0 @@
// Generated by uniffi-bindgen-gecko-js. DO NOT EDIT.
#include "nsString.h"
#include "nsPrintfCString.h"
#include "mozilla/Maybe.h"
#include "mozilla/dom/UniFFIScaffolding.h"
#include "mozilla/dom/ScaffoldingCall.h"
namespace mozilla::uniffi {
using dom::ArrayBuffer;
using dom::GlobalObject;
using dom::RootedDictionary;
using dom::Promise;
using dom::ScaffoldingType;
using dom::Sequence;
using dom::UniFFIPointer;
using dom::UniFFIScaffoldingCallResult;
// Define scaffolding functions from UniFFI
extern "C" {
{%- for ci in ci_list %}
{%- for func in ci.iter_user_ffi_function_definitions() %}
{{ func.rust_return_type() }} {{ func.rust_name() }}({{ func.rust_arg_list() }});
{%- endfor %}
{%- endfor %}
}
// Define pointer types
{%- for ci in ci_list %}
{%- for object in ci.object_definitions() %}
{%- let pointer_type = ci.pointer_type(object) %}
const static mozilla::uniffi::UniFFIPointerType {{ pointer_type }} {
"{{ "{}::{}"|format(ci.namespace(), object.name()) }}"_ns,
{{ object.ffi_object_free().rust_name() }}
};
{%- endfor %}
{%- endfor %}
Maybe<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 func in ci.exposed_functions() %}
case {{ function_ids.get(ci, func) }}: { // {{ function_ids.name(ci, func) }}
using CallHandler = {{ ci.scaffolding_call_handler(func) }};
return Some(CallHandler::CallAsync({{ func.rust_name() }}, aGlobal, aArgs, "{{ func.name() }}: "_ns, aError));
}
{%- endfor %}
{%- endfor %}
}
return Nothing();
}
bool {{ prefix }}CallSync(const GlobalObject& aGlobal, uint64_t aId, const Sequence<ScaffoldingType>& aArgs, RootedDictionary<UniFFIScaffoldingCallResult>& aReturnValue, ErrorResult& aError) {
switch (aId) {
{%- for ci in ci_list %}
{%- for func in ci.exposed_functions() %}
case {{ function_ids.get(ci, func) }}: { // {{ function_ids.name(ci, func) }}
using CallHandler = {{ ci.scaffolding_call_handler(func) }};
CallHandler::CallSync({{ func.rust_name() }}, aGlobal, aArgs, aReturnValue, "{{ func.name() }}: "_ns, aError);
return true;
}
{%- endfor %}
{%- endfor %}
}
return false;
}
Maybe<already_AddRefed<UniFFIPointer>> {{ prefix }}ReadPointer(const GlobalObject& aGlobal, uint64_t aId, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) {
const UniFFIPointerType* type;
switch (aId) {
{%- for ci in ci_list %}
{%- for object in ci.object_definitions() %}
case {{ object_ids.get(ci, object) }}: { // {{ object_ids.name(ci, object) }}
type = &{{ ci.pointer_type(object) }};
break;
}
{%- endfor %}
{%- endfor %}
default:
return Nothing();
}
return Some(UniFFIPointer::Read(aArrayBuff, aPosition, type, aError));
}
bool {{ prefix }}WritePointer(const GlobalObject& aGlobal, uint64_t aId, const UniFFIPointer& aPtr, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) {
const UniFFIPointerType* type;
switch (aId) {
{%- for ci in ci_list %}
{%- for object in ci.object_definitions() %}
case {{ object_ids.get(ci, object) }}: { // {{ object_ids.name(ci, object) }}
type = &{{ ci.pointer_type(object) }};
break;
}
{%- endfor %}
{%- endfor %}
default:
return false;
}
aPtr.Write(aArrayBuff, aPosition, type, aError);
return true;
}
} // namespace mozilla::uniffi

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше