summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi_meta
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/uniffi_meta')
-rw-r--r--third_party/rust/uniffi_meta/.cargo-checksum.json2
-rw-r--r--third_party/rust/uniffi_meta/Cargo.toml5
-rw-r--r--third_party/rust/uniffi_meta/README.md81
-rw-r--r--third_party/rust/uniffi_meta/src/ffi_names.rs13
-rw-r--r--third_party/rust/uniffi_meta/src/group.rs9
-rw-r--r--third_party/rust/uniffi_meta/src/lib.rs65
-rw-r--r--third_party/rust/uniffi_meta/src/metadata.rs13
-rw-r--r--third_party/rust/uniffi_meta/src/reader.rs148
-rw-r--r--third_party/rust/uniffi_meta/src/types.rs22
9 files changed, 275 insertions, 83 deletions
diff --git a/third_party/rust/uniffi_meta/.cargo-checksum.json b/third_party/rust/uniffi_meta/.cargo-checksum.json
index cb02cde83f..31b45ce807 100644
--- a/third_party/rust/uniffi_meta/.cargo-checksum.json
+++ b/third_party/rust/uniffi_meta/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"cb9f8aad563572bd4f12ee234ede6773f189a79ba5bd3bfd7622d3c0ec49d6a3","src/ffi_names.rs":"422bbe9d49d5476de752a9f9b2330f59b37a79e67f19a828caceb64d1bdabff8","src/group.rs":"ae996e6b9f83d459af04eb392e36487d0fe19c7328a395823186cce76a0955ff","src/lib.rs":"a442e2271a0eb538ec1d4fc7573a3acc7e5f366e2b2ac8d0e659fd998fd7d995","src/metadata.rs":"4ae425a8eab7b8c19a6b96c914f2c02c5bee00358888fd55b936fd1fd175a93c","src/reader.rs":"57fb771584491b8e90b01c68f9d53bac7cfa3135888e11e24e14b59312185ff9","src/types.rs":"8c155ed1301e11a365863989e29c2271149048092fb7052ec145f58c948482d5"},"package":"71dc8573a7b1ac4b71643d6da34888273ebfc03440c525121f1b3634ad3417a2"} \ No newline at end of file
+{"files":{"Cargo.toml":"5620cf9840477b158641547703ba353e3ad8427ec7b20b9dd5e5f5fe4df7d6d2","README.md":"37c1af00ec81a9f1bc206ab3578356e5f9ad4077dc46dd1bb623d81d804948b8","src/ffi_names.rs":"ca38b700a0a103c9faaf456ed91b67adf46d4e750aee9e9cd01ad97fb1840494","src/group.rs":"d0a43f3c528aba9403649715981ad3a8849d7a370f4ef9e2d618b88f60a3102f","src/lib.rs":"3f00d5214e2785e4b3045bc48899f6f6b1dce32ab3da6be3ebce716ee9d24c5f","src/metadata.rs":"3f236b337a1fd5082ea9cc4fee6800193a903ee88b81f1c3202843402f122a14","src/reader.rs":"579e2b87d8dd9d703b8811294abfb992621c0a46765800e4db2fad2906db2208","src/types.rs":"c2c5188da8cdf5af7f8496d4660bcfaa971b81ed73b64486c05b47256048544f"},"package":"f7224422c4cfd181c7ca9fca2154abca4d21db962f926f270f996edd38b0c4b8"} \ No newline at end of file
diff --git a/third_party/rust/uniffi_meta/Cargo.toml b/third_party/rust/uniffi_meta/Cargo.toml
index 34999eee18..04d8170011 100644
--- a/third_party/rust/uniffi_meta/Cargo.toml
+++ b/third_party/rust/uniffi_meta/Cargo.toml
@@ -12,9 +12,10 @@
[package]
edition = "2021"
name = "uniffi_meta"
-version = "0.25.3"
+version = "0.27.1"
description = "uniffi_meta"
homepage = "https://mozilla.github.io/uniffi-rs"
+readme = "README.md"
keywords = [
"ffi",
"bindgen",
@@ -32,4 +33,4 @@ version = "1.3"
version = "0.3"
[dependencies.uniffi_checksum_derive]
-version = "0.25.3"
+version = "0.27.1"
diff --git a/third_party/rust/uniffi_meta/README.md b/third_party/rust/uniffi_meta/README.md
new file mode 100644
index 0000000000..64ac3486a3
--- /dev/null
+++ b/third_party/rust/uniffi_meta/README.md
@@ -0,0 +1,81 @@
+# UniFFI - a multi-language bindings generator for Rust
+
+UniFFI is a toolkit for building cross-platform software components in Rust.
+
+For the impatient, see [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/)
+or [**the UniFFI examples**](https://github.com/mozilla/uniffi-rs/tree/main/examples#example-uniffi-components).
+
+By writing your core business logic in Rust and describing its interface in an "object model",
+you can use UniFFI to help you:
+
+* Compile your Rust code into a shared library for use on different target platforms.
+* Generate bindings to load and use the library from different target languages.
+
+You can describe your object model in an [interface definition file](https://mozilla.github.io/uniffi-rs/udl_file_spec.html)
+or [by using proc-macros](https://mozilla.github.io/uniffi-rs/proc_macro/index.html).
+
+UniFFI is currently used extensively by Mozilla in Firefox mobile and desktop browsers;
+written once in Rust, auto-generated bindings allow that functionality to be called
+from both Kotlin (for Android apps) and Swift (for iOS apps).
+It also has a growing community of users shipping various cool things to many users.
+
+UniFFI comes with support for **Kotlin**, **Swift**, **Python** and **Ruby** with 3rd party bindings available for **C#** and **Golang**.
+Additional foreign language bindings can be developed externally and we welcome contributions to list them here.
+See [Third-party foreign language bindings](#third-party-foreign-language-bindings).
+
+## User Guide
+
+You can read more about using the tool in [**the UniFFI user guide**](https://mozilla.github.io/uniffi-rs/).
+
+We consider it ready for production use, but UniFFI is a long way from a 1.0 release with lots of internal work still going on.
+We try hard to avoid breaking simple consumers, but more advanced things might break as you upgrade over time.
+
+### Etymology and Pronunciation
+
+ˈjuːnɪfaɪ. Pronounced to rhyme with "unify".
+
+A portmanteau word that also puns with "unify", to signify the joining of one codebase accessed from many languages.
+
+uni - [Latin ūni-, from ūnus, one]
+FFI - [Abbreviation, Foreign Function Interface]
+
+## Alternative tools
+
+Other tools we know of which try and solve a similarly shaped problem are:
+
+* [Diplomat](https://github.com/rust-diplomat/diplomat/) - see our [writeup of
+ the different approach taken by that tool](docs/diplomat-and-macros.md)
+* [Interoptopus](https://github.com/ralfbiedert/interoptopus/)
+
+(Please open a PR if you think other tools should be listed!)
+
+## Third-party foreign language bindings
+
+* [Kotlin Multiplatform support](https://gitlab.com/trixnity/uniffi-kotlin-multiplatform-bindings). The repository contains Kotlin Multiplatform bindings generation for UniFFI, letting you target both JVM and Native.
+* [Go bindings](https://github.com/NordSecurity/uniffi-bindgen-go)
+* [C# bindings](https://github.com/NordSecurity/uniffi-bindgen-cs)
+* [Dart bindings](https://github.com/NiallBunting/uniffi-rs-dart)
+
+### External resources
+
+There are a few third-party resources that make it easier to work with UniFFI:
+
+* [Plugin support for `.udl` files](https://github.com/Lonami/uniffi-dl) for the IDEA platform ([*uniffi-dl* in the JetBrains marketplace](https://plugins.jetbrains.com/plugin/20527-uniffi-dl)). It provides syntax highlighting, code folding, code completion, reference resolution and navigation (among others features) for the [UniFFI Definition Language (UDL)](https://mozilla.github.io/uniffi-rs/).
+* [cargo swift](https://github.com/antoniusnaumann/cargo-swift), a cargo plugin to build a Swift Package from Rust code. It provides an init command for setting up a UniFFI crate and a package command for building a Swift package from Rust code - without the need for additional configuration or build scripts.
+* [Cargo NDK Gradle Plugin](https://github.com/willir/cargo-ndk-android-gradle) allows you to build Rust code using [`cargo-ndk`](https://github.com/bbqsrc/cargo-ndk), which generally makes Android library builds less painful.
+* [`uniffi-starter`](https://github.com/ianthetechie/uniffi-starter) is a minimal project demonstrates a wide range of UniFFI in a complete project in a compact manner. It includes a full Android library build process, an XCFramework generation script, and example Swift package structure.
+
+(Please open a PR if you think other resources should be listed!)
+
+## Contributing
+
+If this tool sounds interesting to you, please help us develop it! You can:
+
+* View the [contributor guidelines](./docs/contributing.md).
+* File or work on [issues](https://github.com/mozilla/uniffi-rs/issues) here in GitHub.
+* Join discussions in the [#uniffi:mozilla.org](https://matrix.to/#/#uniffi:mozilla.org)
+ room on Matrix.
+
+## Code of Conduct
+
+This project is governed by Mozilla's [Community Participation Guidelines](./CODE_OF_CONDUCT.md).
diff --git a/third_party/rust/uniffi_meta/src/ffi_names.rs b/third_party/rust/uniffi_meta/src/ffi_names.rs
index 44a5bc3e63..5c931a09e3 100644
--- a/third_party/rust/uniffi_meta/src/ffi_names.rs
+++ b/third_party/rust/uniffi_meta/src/ffi_names.rs
@@ -33,6 +33,12 @@ pub fn method_symbol_name(namespace: &str, object_name: &str, name: &str) -> Str
format!("uniffi_{namespace}_fn_method_{object_name}_{name}")
}
+/// FFI symbol name for the `clone` function for an object.
+pub fn clone_fn_symbol_name(namespace: &str, object_name: &str) -> String {
+ let object_name = object_name.to_ascii_lowercase();
+ format!("uniffi_{namespace}_fn_clone_{object_name}")
+}
+
/// FFI symbol name for the `free` function for an object.
pub fn free_fn_symbol_name(namespace: &str, object_name: &str) -> String {
let object_name = object_name.to_ascii_lowercase();
@@ -40,9 +46,12 @@ pub fn free_fn_symbol_name(namespace: &str, object_name: &str) -> String {
}
/// FFI symbol name for the `init_callback` function for a callback interface
-pub fn init_callback_fn_symbol_name(namespace: &str, callback_interface_name: &str) -> String {
+pub fn init_callback_vtable_fn_symbol_name(
+ namespace: &str,
+ callback_interface_name: &str,
+) -> String {
let callback_interface_name = callback_interface_name.to_ascii_lowercase();
- format!("uniffi_{namespace}_fn_init_callback_{callback_interface_name}")
+ format!("uniffi_{namespace}_fn_init_callback_vtable_{callback_interface_name}")
}
/// FFI checksum symbol name for a top-level function
diff --git a/third_party/rust/uniffi_meta/src/group.rs b/third_party/rust/uniffi_meta/src/group.rs
index f0be2e5a98..a41776bf8a 100644
--- a/third_party/rust/uniffi_meta/src/group.rs
+++ b/third_party/rust/uniffi_meta/src/group.rs
@@ -18,6 +18,7 @@ pub fn create_metadata_groups(items: &[Metadata]) -> MetadataGroupMap {
Metadata::Namespace(namespace) => {
let group = MetadataGroup {
namespace: namespace.clone(),
+ namespace_docstring: None,
items: BTreeSet::new(),
};
Some((namespace.crate_name.clone(), group))
@@ -29,6 +30,7 @@ pub fn create_metadata_groups(items: &[Metadata]) -> MetadataGroupMap {
};
let group = MetadataGroup {
namespace,
+ namespace_docstring: None,
items: BTreeSet::new(),
};
Some((udl.module_path.clone(), group))
@@ -63,6 +65,7 @@ pub fn group_metadata(group_map: &mut MetadataGroupMap, items: Vec<Metadata>) ->
#[derive(Debug)]
pub struct MetadataGroup {
pub namespace: NamespaceMetadata,
+ pub namespace_docstring: Option<String>,
pub items: BTreeSet<Metadata>,
}
@@ -127,12 +130,6 @@ impl<'a> ExternalTypeConverter<'a> {
..meta
}),
Metadata::Enum(meta) => Metadata::Enum(self.convert_enum(meta)),
- Metadata::Error(meta) => Metadata::Error(match meta {
- ErrorMetadata::Enum { enum_, is_flat } => ErrorMetadata::Enum {
- enum_: self.convert_enum(enum_),
- is_flat,
- },
- }),
_ => item,
}
}
diff --git a/third_party/rust/uniffi_meta/src/lib.rs b/third_party/rust/uniffi_meta/src/lib.rs
index e486d84d89..90f7b2d3cd 100644
--- a/third_party/rust/uniffi_meta/src/lib.rs
+++ b/third_party/rust/uniffi_meta/src/lib.rs
@@ -23,7 +23,7 @@ mod metadata;
// `docs/uniffi-versioning.md` for details.
//
// Once we get to 1.0, then we'll need to update the scheme to something like 100 + major_version
-pub const UNIFFI_CONTRACT_VERSION: u32 = 24;
+pub const UNIFFI_CONTRACT_VERSION: u32 = 26;
/// Similar to std::hash::Hash.
///
@@ -143,6 +143,7 @@ pub struct FnMetadata {
pub return_type: Option<Type>,
pub throws: Option<Type>,
pub checksum: Option<u16>,
+ pub docstring: Option<String>,
}
impl FnMetadata {
@@ -160,9 +161,11 @@ pub struct ConstructorMetadata {
pub module_path: String,
pub self_name: String,
pub name: String,
+ pub is_async: bool,
pub inputs: Vec<FnParamMetadata>,
pub throws: Option<Type>,
pub checksum: Option<u16>,
+ pub docstring: Option<String>,
}
impl ConstructorMetadata {
@@ -190,6 +193,7 @@ pub struct MethodMetadata {
pub throws: Option<Type>,
pub takes_self_by_arc: bool, // unused except by rust udl bindgen.
pub checksum: Option<u16>,
+ pub docstring: Option<String>,
}
impl MethodMetadata {
@@ -216,6 +220,7 @@ pub struct TraitMethodMetadata {
pub throws: Option<Type>,
pub takes_self_by_arc: bool, // unused except by rust udl bindgen.
pub checksum: Option<u16>,
+ pub docstring: Option<String>,
}
impl TraitMethodMetadata {
@@ -266,7 +271,17 @@ pub enum LiteralMetadata {
Enum(String, Type),
EmptySequence,
EmptyMap,
- Null,
+ None,
+ Some { inner: Box<LiteralMetadata> },
+}
+
+impl LiteralMetadata {
+ pub fn new_uint(v: u64) -> Self {
+ LiteralMetadata::UInt(v, Radix::Decimal, Type::UInt64)
+ }
+ pub fn new_int(v: i64) -> Self {
+ LiteralMetadata::Int(v, Radix::Decimal, Type::Int64)
+ }
}
// Represent the radix of integer literal values.
@@ -283,6 +298,7 @@ pub struct RecordMetadata {
pub module_path: String,
pub name: String,
pub fields: Vec<FieldMetadata>,
+ pub docstring: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -290,19 +306,26 @@ pub struct FieldMetadata {
pub name: String,
pub ty: Type,
pub default: Option<LiteralMetadata>,
+ pub docstring: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct EnumMetadata {
pub module_path: String,
pub name: String,
+ pub forced_flatness: Option<bool>,
pub variants: Vec<VariantMetadata>,
+ pub discr_type: Option<Type>,
+ pub non_exhaustive: bool,
+ pub docstring: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct VariantMetadata {
pub name: String,
+ pub discr: Option<LiteralMetadata>,
pub fields: Vec<FieldMetadata>,
+ pub docstring: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -310,15 +333,25 @@ pub struct ObjectMetadata {
pub module_path: String,
pub name: String,
pub imp: types::ObjectImpl,
+ pub docstring: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct CallbackInterfaceMetadata {
pub module_path: String,
pub name: String,
+ pub docstring: Option<String>,
}
impl ObjectMetadata {
+ /// FFI symbol name for the `clone` function for this object.
+ ///
+ /// This function is used to increment the reference count before lowering an object to pass
+ /// back to Rust.
+ pub fn clone_ffi_symbol_name(&self) -> String {
+ clone_fn_symbol_name(&self.module_path, &self.name)
+ }
+
/// FFI symbol name for the `free` function for this object.
///
/// This function is used to free the memory used by this object.
@@ -368,6 +401,7 @@ impl UniffiTraitMetadata {
}
#[repr(u8)]
+#[derive(Eq, PartialEq, Hash)]
pub enum UniffiTraitDiscriminants {
Debug,
Display,
@@ -388,25 +422,6 @@ impl UniffiTraitDiscriminants {
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-pub enum ErrorMetadata {
- Enum { enum_: EnumMetadata, is_flat: bool },
-}
-
-impl ErrorMetadata {
- pub fn name(&self) -> &String {
- match self {
- Self::Enum { enum_, .. } => &enum_.name,
- }
- }
-
- pub fn module_path(&self) -> &String {
- match self {
- Self::Enum { enum_, .. } => &enum_.module_path,
- }
- }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct CustomTypeMetadata {
pub module_path: String,
pub name: String,
@@ -433,7 +448,6 @@ pub enum Metadata {
CallbackInterface(CallbackInterfaceMetadata),
Record(RecordMetadata),
Enum(EnumMetadata),
- Error(ErrorMetadata),
Constructor(ConstructorMetadata),
Method(MethodMetadata),
TraitMethod(TraitMethodMetadata),
@@ -458,7 +472,6 @@ impl Metadata {
Metadata::Object(meta) => &meta.module_path,
Metadata::CallbackInterface(meta) => &meta.module_path,
Metadata::TraitMethod(meta) => &meta.module_path,
- Metadata::Error(meta) => meta.module_path(),
Metadata::CustomType(meta) => &meta.module_path,
Metadata::UniffiTrait(meta) => meta.module_path(),
}
@@ -507,12 +520,6 @@ impl From<EnumMetadata> for Metadata {
}
}
-impl From<ErrorMetadata> for Metadata {
- fn from(e: ErrorMetadata) -> Self {
- Self::Error(e)
- }
-}
-
impl From<ObjectMetadata> for Metadata {
fn from(v: ObjectMetadata) -> Self {
Self::Object(v)
diff --git a/third_party/rust/uniffi_meta/src/metadata.rs b/third_party/rust/uniffi_meta/src/metadata.rs
index 6e490a4866..9cfb77a244 100644
--- a/third_party/rust/uniffi_meta/src/metadata.rs
+++ b/third_party/rust/uniffi_meta/src/metadata.rs
@@ -7,7 +7,7 @@
// `uniffi_core`.
// This is the easy way out of that issue and is a temporary hacky solution.
-/// Metadata constants, make sure to keep this in sync with copy in `uniffi_meta::reader`
+/// Metadata constants, make sure to keep this in sync with copy in `uniffi_core::metadata`
pub mod codes {
// Top-level metadata item codes
pub const FUNC: u8 = 0;
@@ -15,13 +15,14 @@ pub mod codes {
pub const RECORD: u8 = 2;
pub const ENUM: u8 = 3;
pub const INTERFACE: u8 = 4;
- pub const ERROR: u8 = 5;
pub const NAMESPACE: u8 = 6;
pub const CONSTRUCTOR: u8 = 7;
pub const UDL_FILE: u8 = 8;
pub const CALLBACK_INTERFACE: u8 = 9;
pub const TRAIT_METHOD: u8 = 10;
pub const UNIFFI_TRAIT: u8 = 11;
+ pub const TRAIT_INTERFACE: u8 = 12;
+ pub const CALLBACK_TRAIT_INTERFACE: u8 = 13;
//pub const UNKNOWN: u8 = 255;
// Type codes
@@ -49,8 +50,8 @@ pub mod codes {
pub const TYPE_CALLBACK_INTERFACE: u8 = 21;
pub const TYPE_CUSTOM: u8 = 22;
pub const TYPE_RESULT: u8 = 23;
- //pub const TYPE_FUTURE: u8 = 24;
- pub const TYPE_FOREIGN_EXECUTOR: u8 = 25;
+ pub const TYPE_TRAIT_INTERFACE: u8 = 24;
+ pub const TYPE_CALLBACK_TRAIT_INTERFACE: u8 = 25;
pub const TYPE_UNIT: u8 = 255;
// Literal codes
@@ -58,7 +59,9 @@ pub mod codes {
pub const LIT_INT: u8 = 1;
pub const LIT_FLOAT: u8 = 2;
pub const LIT_BOOL: u8 = 3;
- pub const LIT_NULL: u8 = 4;
+ pub const LIT_NONE: u8 = 4;
+ pub const LIT_SOME: u8 = 5;
+ pub const LIT_EMPTY_SEQ: u8 = 6;
}
// Create a checksum for a MetadataBuffer
diff --git a/third_party/rust/uniffi_meta/src/reader.rs b/third_party/rust/uniffi_meta/src/reader.rs
index bf6525f2b5..6fec6cb3a3 100644
--- a/third_party/rust/uniffi_meta/src/reader.rs
+++ b/third_party/rust/uniffi_meta/src/reader.rs
@@ -52,9 +52,10 @@ impl<'a> MetadataReader<'a> {
codes::CONSTRUCTOR => self.read_constructor()?.into(),
codes::METHOD => self.read_method()?.into(),
codes::RECORD => self.read_record()?.into(),
- codes::ENUM => self.read_enum(false)?.into(),
- codes::ERROR => self.read_error()?.into(),
- codes::INTERFACE => self.read_object()?.into(),
+ codes::ENUM => self.read_enum()?.into(),
+ codes::INTERFACE => self.read_object(ObjectImpl::Struct)?.into(),
+ codes::TRAIT_INTERFACE => self.read_object(ObjectImpl::Trait)?.into(),
+ codes::CALLBACK_TRAIT_INTERFACE => self.read_object(ObjectImpl::CallbackTrait)?.into(),
codes::CALLBACK_INTERFACE => self.read_callback_interface()?.into(),
codes::TRAIT_METHOD => self.read_trait_method()?.into(),
codes::UNIFFI_TRAIT => self.read_uniffi_trait()?.into(),
@@ -80,6 +81,17 @@ impl<'a> MetadataReader<'a> {
}
}
+ fn read_u16(&mut self) -> Result<u16> {
+ if self.buf.len() >= 2 {
+ // read the value as little-endian
+ let value = u16::from_le_bytes([self.buf[0], self.buf[1]]);
+ self.buf = &self.buf[2..];
+ Ok(value)
+ } else {
+ bail!("Not enough data left in buffer to read a u16 value");
+ }
+ }
+
fn read_u32(&mut self) -> Result<u32> {
if self.buf.len() >= 4 {
// read the value as little-endian
@@ -105,6 +117,17 @@ impl<'a> MetadataReader<'a> {
String::from_utf8(slice.into()).context("Invalid string data")
}
+ fn read_long_string(&mut self) -> Result<String> {
+ let size = self.read_u16()? as usize;
+ let slice;
+ (slice, self.buf) = self.buf.split_at(size);
+ String::from_utf8(slice.into()).context("Invalid string data")
+ }
+
+ fn read_optional_long_string(&mut self) -> Result<Option<String>> {
+ Ok(Some(self.read_long_string()?).filter(|str| !str.is_empty()))
+ }
+
fn read_type(&mut self) -> Result<Type> {
let value = self.read_u8()?;
Ok(match value {
@@ -122,7 +145,6 @@ impl<'a> MetadataReader<'a> {
codes::TYPE_STRING => Type::String,
codes::TYPE_DURATION => Type::Duration,
codes::TYPE_SYSTEM_TIME => Type::Timestamp,
- codes::TYPE_FOREIGN_EXECUTOR => Type::ForeignExecutor,
codes::TYPE_RECORD => Type::Record {
module_path: self.read_string()?,
name: self.read_string()?,
@@ -134,7 +156,17 @@ impl<'a> MetadataReader<'a> {
codes::TYPE_INTERFACE => Type::Object {
module_path: self.read_string()?,
name: self.read_string()?,
- imp: ObjectImpl::from_is_trait(self.read_bool()?),
+ imp: ObjectImpl::Struct,
+ },
+ codes::TYPE_TRAIT_INTERFACE => Type::Object {
+ module_path: self.read_string()?,
+ name: self.read_string()?,
+ imp: ObjectImpl::Trait,
+ },
+ codes::TYPE_CALLBACK_TRAIT_INTERFACE => Type::Object {
+ module_path: self.read_string()?,
+ name: self.read_string()?,
+ imp: ObjectImpl::CallbackTrait,
},
codes::TYPE_CALLBACK_INTERFACE => Type::CallbackInterface {
module_path: self.read_string()?,
@@ -198,6 +230,7 @@ impl<'a> MetadataReader<'a> {
let is_async = self.read_bool()?;
let inputs = self.read_inputs()?;
let (return_type, throws) = self.read_return_type()?;
+ let docstring = self.read_optional_long_string()?;
Ok(FnMetadata {
module_path,
name,
@@ -205,6 +238,7 @@ impl<'a> MetadataReader<'a> {
inputs,
return_type,
throws,
+ docstring,
checksum: self.calc_checksum(),
})
}
@@ -213,8 +247,10 @@ impl<'a> MetadataReader<'a> {
let module_path = self.read_string()?;
let self_name = self.read_string()?;
let name = self.read_string()?;
+ let is_async = self.read_bool()?;
let inputs = self.read_inputs()?;
let (return_type, throws) = self.read_return_type()?;
+ let docstring = self.read_optional_long_string()?;
return_type
.filter(|t| {
@@ -228,10 +264,12 @@ impl<'a> MetadataReader<'a> {
Ok(ConstructorMetadata {
module_path,
self_name,
+ is_async,
name,
inputs,
throws,
checksum: self.calc_checksum(),
+ docstring,
})
}
@@ -242,6 +280,7 @@ impl<'a> MetadataReader<'a> {
let is_async = self.read_bool()?;
let inputs = self.read_inputs()?;
let (return_type, throws) = self.read_return_type()?;
+ let docstring = self.read_optional_long_string()?;
Ok(MethodMetadata {
module_path,
self_name,
@@ -252,6 +291,7 @@ impl<'a> MetadataReader<'a> {
throws,
takes_self_by_arc: false, // not emitted by macros
checksum: self.calc_checksum(),
+ docstring,
})
}
@@ -260,13 +300,25 @@ impl<'a> MetadataReader<'a> {
module_path: self.read_string()?,
name: self.read_string()?,
fields: self.read_fields()?,
+ docstring: self.read_optional_long_string()?,
})
}
- fn read_enum(&mut self, is_flat_error: bool) -> Result<EnumMetadata> {
+ fn read_enum(&mut self) -> Result<EnumMetadata> {
let module_path = self.read_string()?;
let name = self.read_string()?;
- let variants = if is_flat_error {
+ let forced_flatness = match self.read_u8()? {
+ 0 => None,
+ 1 => Some(false),
+ 2 => Some(true),
+ _ => unreachable!("invalid flatness"),
+ };
+ let discr_type = if self.read_bool()? {
+ Some(self.read_type()?)
+ } else {
+ None
+ };
+ let variants = if forced_flatness == Some(true) {
self.read_flat_variants()?
} else {
self.read_variants()?
@@ -275,21 +327,20 @@ impl<'a> MetadataReader<'a> {
Ok(EnumMetadata {
module_path,
name,
+ forced_flatness,
+ discr_type,
variants,
+ non_exhaustive: self.read_bool()?,
+ docstring: self.read_optional_long_string()?,
})
}
- fn read_error(&mut self) -> Result<ErrorMetadata> {
- let is_flat = self.read_bool()?;
- let enum_ = self.read_enum(is_flat)?;
- Ok(ErrorMetadata::Enum { enum_, is_flat })
- }
-
- fn read_object(&mut self) -> Result<ObjectMetadata> {
+ fn read_object(&mut self, imp: ObjectImpl) -> Result<ObjectMetadata> {
Ok(ObjectMetadata {
module_path: self.read_string()?,
name: self.read_string()?,
- imp: ObjectImpl::from_is_trait(self.read_bool()?),
+ imp,
+ docstring: self.read_optional_long_string()?,
})
}
@@ -322,6 +373,7 @@ impl<'a> MetadataReader<'a> {
Ok(CallbackInterfaceMetadata {
module_path: self.read_string()?,
name: self.read_string()?,
+ docstring: self.read_optional_long_string()?,
})
}
@@ -333,6 +385,7 @@ impl<'a> MetadataReader<'a> {
let is_async = self.read_bool()?;
let inputs = self.read_inputs()?;
let (return_type, throws) = self.read_return_type()?;
+ let docstring = self.read_optional_long_string()?;
Ok(TraitMethodMetadata {
module_path,
trait_name,
@@ -344,6 +397,7 @@ impl<'a> MetadataReader<'a> {
throws,
takes_self_by_arc: false, // not emitted by macros
checksum: self.calc_checksum(),
+ docstring,
})
}
@@ -353,8 +407,13 @@ impl<'a> MetadataReader<'a> {
.map(|_| {
let name = self.read_string()?;
let ty = self.read_type()?;
- let default = self.read_default(&name, &ty)?;
- Ok(FieldMetadata { name, ty, default })
+ let default = self.read_optional_default(&name, &ty)?;
+ Ok(FieldMetadata {
+ name,
+ ty,
+ default,
+ docstring: self.read_optional_long_string()?,
+ })
})
.collect()
}
@@ -365,7 +424,9 @@ impl<'a> MetadataReader<'a> {
.map(|_| {
Ok(VariantMetadata {
name: self.read_string()?,
+ discr: self.read_optional_default("<variant-value>", &Type::UInt64)?,
fields: self.read_fields()?,
+ docstring: self.read_optional_long_string()?,
})
})
.collect()
@@ -377,7 +438,9 @@ impl<'a> MetadataReader<'a> {
.map(|_| {
Ok(VariantMetadata {
name: self.read_string()?,
+ discr: None,
fields: vec![],
+ docstring: self.read_optional_long_string()?,
})
})
.collect()
@@ -387,13 +450,16 @@ impl<'a> MetadataReader<'a> {
let len = self.read_u8()?;
(0..len)
.map(|_| {
+ let name = self.read_string()?;
+ let ty = self.read_type()?;
+ let default = self.read_optional_default(&name, &ty)?;
Ok(FnParamMetadata {
- name: self.read_string()?,
- ty: self.read_type()?,
+ name,
+ ty,
+ default,
// not emitted by macros
by_ref: false,
optional: false,
- default: None,
})
})
.collect()
@@ -405,14 +471,18 @@ impl<'a> MetadataReader<'a> {
Some(checksum_metadata(metadata_buf))
}
- fn read_default(&mut self, name: &str, ty: &Type) -> Result<Option<LiteralMetadata>> {
- let has_default = self.read_bool()?;
- if !has_default {
- return Ok(None);
+ fn read_optional_default(&mut self, name: &str, ty: &Type) -> Result<Option<LiteralMetadata>> {
+ if self.read_bool()? {
+ Ok(Some(self.read_default(name, ty)?))
+ } else {
+ Ok(None)
}
+ }
+ fn read_default(&mut self, name: &str, ty: &Type) -> Result<LiteralMetadata> {
let literal_kind = self.read_u8()?;
- Ok(Some(match literal_kind {
+
+ Ok(match literal_kind {
codes::LIT_STR => {
ensure!(
matches!(ty, Type::String),
@@ -422,12 +492,24 @@ impl<'a> MetadataReader<'a> {
}
codes::LIT_INT => {
let base10_digits = self.read_string()?;
+ // procmacros emit the type for discriminant values based purely on whether the constant
+ // is positive or negative.
+ let ty = if !base10_digits.is_empty()
+ && base10_digits.as_bytes()[0] == b'-'
+ && ty == &Type::UInt64
+ {
+ &Type::Int64
+ } else {
+ ty
+ };
macro_rules! parse_int {
($ty:ident, $variant:ident) => {
LiteralMetadata::$variant(
base10_digits
.parse::<$ty>()
- .with_context(|| format!("parsing default for field {name}"))?
+ .with_context(|| {
+ format!("parsing default for field {name}: {base10_digits}")
+ })?
.into(),
Radix::Decimal,
ty.to_owned(),
@@ -458,8 +540,18 @@ impl<'a> MetadataReader<'a> {
}
},
codes::LIT_BOOL => LiteralMetadata::Boolean(self.read_bool()?),
- codes::LIT_NULL => LiteralMetadata::Null,
+ codes::LIT_NONE => match ty {
+ Type::Optional { .. } => LiteralMetadata::None,
+ _ => bail!("field {name} of type {ty:?} can't have a default value of None"),
+ },
+ codes::LIT_SOME => match ty {
+ Type::Optional { inner_type, .. } => LiteralMetadata::Some {
+ inner: Box::new(self.read_default(name, inner_type)?),
+ },
+ _ => bail!("field {name} of type {ty:?} can't have a default value of None"),
+ },
+ codes::LIT_EMPTY_SEQ => LiteralMetadata::EmptySequence,
_ => bail!("Unexpected literal kind code: {literal_kind:?}"),
- }))
+ })
}
}
diff --git a/third_party/rust/uniffi_meta/src/types.rs b/third_party/rust/uniffi_meta/src/types.rs
index 24f8a6f2a8..51bf156b50 100644
--- a/third_party/rust/uniffi_meta/src/types.rs
+++ b/third_party/rust/uniffi_meta/src/types.rs
@@ -21,8 +21,12 @@ use crate::Checksum;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Checksum, Ord, PartialOrd)]
pub enum ObjectImpl {
+ // A single Rust type
Struct,
+ // A trait that's can be implemented by Rust types
Trait,
+ // A trait + a callback interface -- can be implemented by both Rust and foreign types.
+ CallbackTrait,
}
impl ObjectImpl {
@@ -31,27 +35,26 @@ impl ObjectImpl {
/// Includes `r#`, traits get a leading `dyn`. If we ever supported associated types, then
/// this would also include them.
pub fn rust_name_for(&self, name: &str) -> String {
- if self == &ObjectImpl::Trait {
+ if self.is_trait_interface() {
format!("dyn r#{name}")
} else {
format!("r#{name}")
}
}
- // uniffi_meta and procmacro support tend to carry around `is_trait` bools. This makes that
- // mildly less painful
- pub fn from_is_trait(is_trait: bool) -> Self {
- if is_trait {
- ObjectImpl::Trait
- } else {
- ObjectImpl::Struct
- }
+ pub fn is_trait_interface(&self) -> bool {
+ matches!(self, Self::Trait | Self::CallbackTrait)
+ }
+
+ pub fn has_callback_interface(&self) -> bool {
+ matches!(self, Self::CallbackTrait)
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Checksum, Ord, PartialOrd)]
pub enum ExternalKind {
Interface,
+ Trait,
// Either a record or enum
DataClass,
}
@@ -85,7 +88,6 @@ pub enum Type {
// How the object is implemented.
imp: ObjectImpl,
},
- ForeignExecutor,
// Types defined in the component API, each of which has a string name.
Record {
module_path: String,