Skip to content

Commit e61c88c

Browse files
committed
Adding BindingsIr
This is a reimangining of the ComponentInterface, modeled after a compiler pipeline. The differences are: - Data-oriented API. It has `pub` fields rather than getter methods. - Tree-like. Fields represent nodes in the tree. You can understand `BindingsIr` by following the fields. - Data is stored directly in the nodes, for example types now have an `is_used_as_error` field instead of having to lookup the type name in `ComponentInterface::errors`. - Each node contains a `LanguageData` container. Bindings generators will put language-specific data in here as part of the bindings IR specialization process. For example: `type_name`, `ffi_converter` and `ffi_type_name`. To accomplish this, `Type`, `FfiType` and `Literal` are now structs, which store a `kind` enum. - It tries to make a stronger distinction between definitions and references to those definitions. - Type and FFI types are sorted in dependency order. This replaces the the Python bindings code that does something similar to avoid forward references. Languages can opt-in to the new API by converting the `ComponentInterface` into a `BindingsIr`. At some point we start converting the metadata directly to `BindingsIr` and remove a ton of ComponentInterface code. Let's make sure to give external bindings authors time to move to the new system.
1 parent ffcdb23 commit e61c88c

File tree

12 files changed

+1262
-184
lines changed

12 files changed

+1262
-184
lines changed

uniffi_bindgen/src/interface/ir/from_ci.rs

+521
Large diffs are not rendered by default.
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
mod from_ci;
6+
mod nodes;
7+
mod sort;
8+
9+
pub use nodes::*;
10+
11+
// Note: the interface code is currently in a bit of a transition state. Most languages are still
12+
// using the `ComponentInterface` to render their bindings, but we plan to switch them over to this
13+
// system.
14+
//
15+
// Once we do that, we can rework the metadata code to generate a `BindingsIr` directly,
16+
// delete a ton of the older code, and consider folding the contents of the `ir` module into
17+
// `interface`.

uniffi_bindgen/src/interface/ir/nodes/dataclasses.rs

+32-29
Original file line numberDiff line numberDiff line change
@@ -2,57 +2,60 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5+
use uniffi_meta::EnumShape;
6+
7+
use super::{Literal, Type};
8+
59
/// Represents a "data class" style object, for passing around complex values.
610
///
711
/// In the FFI these are represented as a byte buffer, which one side explicitly
812
/// serializes the data into and the other serializes it out of. So I guess they're
913
/// kind of like "pass by clone" values.
10-
#[derive(Debug, Clone, PartialEq, Eq, Checksum)]
14+
#[derive(Debug, Clone)]
1115
pub struct Record {
12-
pub(super) name: String,
13-
pub(super) module_path: String,
14-
pub(super) remote: bool,
15-
pub(super) fields: Vec<Field>,
16-
#[checksum_ignore]
17-
pub(super) docstring: Option<String>,
16+
pub name: String,
17+
pub module_path: String,
18+
pub remote: bool,
19+
pub fields: Vec<Field>,
20+
pub docstring: Option<String>,
21+
pub self_type: Type,
1822
}
1923

2024
// Represents an individual field on a Record.
21-
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Checksum)]
25+
#[derive(Debug, Clone)]
2226
pub struct Field {
23-
pub(super) name: String,
24-
pub(super) type_: Type,
25-
pub(super) default: Option<Literal>,
26-
#[checksum_ignore]
27-
pub(super) docstring: Option<String>,
27+
pub name: String,
28+
pub ty: Type,
29+
pub default: Option<Literal>,
30+
pub docstring: Option<String>,
2831
}
2932

3033
/// Represents an enum with named variants, each of which may have named
3134
/// and typed fields.
3235
///
3336
/// Enums are passed across the FFI by serializing to a bytebuffer, with a
3437
/// i32 indicating the variant followed by the serialization of each field.
35-
#[derive(Debug, Clone, PartialEq, Eq, Checksum)]
38+
#[derive(Debug, Clone)]
3639
pub struct Enum {
37-
pub(super) name: String,
38-
pub(super) module_path: String,
39-
pub(super) remote: bool,
40-
pub(super) discr_type: Option<Type>,
41-
pub(super) variants: Vec<Variant>,
42-
pub(super) shape: EnumShape,
43-
pub(super) non_exhaustive: bool,
44-
#[checksum_ignore]
45-
pub(super) docstring: Option<String>,
40+
pub name: String,
41+
pub module_path: String,
42+
pub remote: bool,
43+
pub discr_type: Option<Type>,
44+
pub variants: Vec<Variant>,
45+
pub shape: EnumShape,
46+
pub non_exhaustive: bool,
47+
pub docstring: Option<String>,
48+
pub self_type: Type,
4649
}
4750

4851
/// Represents an individual variant in an Enum.
4952
///
5053
/// Each variant has a name and zero or more fields.
51-
#[derive(Debug, Clone, Default, PartialEq, Eq, Checksum)]
54+
#[derive(Debug, Clone)]
5255
pub struct Variant {
53-
pub(super) name: String,
54-
pub(super) discr: Option<Literal>,
55-
pub(super) fields: Vec<Field>,
56-
#[checksum_ignore]
57-
pub(super) docstring: Option<String>,
56+
pub name: String,
57+
pub discr: Literal,
58+
pub fields: Vec<Field>,
59+
pub enum_shape: EnumShape,
60+
pub docstring: Option<String>,
5861
}

uniffi_bindgen/src/interface/ir/nodes/ffi.rs

+69-28
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
/// An Ffi definition
5+
/// Represents an Ffi definition
66
#[derive(Debug, Clone)]
77
pub enum FfiDefinition {
8+
// Scaffolding function exported in the library
89
Function(FfiFunction),
9-
CallbackFunction(FfiCallbackFunction),
10+
// Function type, for function pointers
11+
FunctionType(FfiFunctionType),
12+
// FFI struct definition
1013
Struct(FfiStruct),
1114
}
1215

@@ -18,52 +21,53 @@ pub enum FfiDefinition {
1821
/// some built-in `FfiFunction` helpers for use in the foreign language bindings.
1922
#[derive(Debug, Clone)]
2023
pub struct FfiFunction {
21-
pub(super) name: String,
22-
pub(super) is_async: bool,
23-
pub(super) arguments: Vec<FfiArgument>,
24-
pub(super) return_type: Option<FfiType>,
25-
pub(super) has_rust_call_status_arg: bool,
24+
pub name: String,
25+
pub is_async: bool,
26+
pub arguments: Vec<FfiArgument>,
27+
pub return_type: Option<FfiType>,
28+
pub has_rust_call_status_arg: bool,
2629
/// Used by C# generator to differentiate the free function and call it with void*
2730
/// instead of C# `SafeHandle` type. See <https://github.com/mozilla/uniffi-rs/pull/1488>.
28-
pub(super) is_object_free_function: bool,
31+
pub is_object_free_function: bool,
2932
}
3033

3134
/// Represents an "extern C"-style callback function
3235
///
3336
/// These are defined in the foreign code and passed to Rust as a function pointer.
34-
#[derive(Debug, Default, Clone)]
35-
pub struct FfiCallbackFunction {
37+
#[derive(Debug, Clone)]
38+
pub struct FfiFunctionType {
3639
// Name for this function type. This matches the value inside `FfiType::Callback`
37-
pub(super) name: String,
38-
pub(super) arguments: Vec<FfiArgument>,
39-
pub(super) return_type: Option<FfiType>,
40-
pub(super) has_rust_call_status_arg: bool,
40+
pub name: String,
41+
pub arguments: Vec<FfiArgument>,
42+
pub return_type: Option<FfiType>,
43+
pub has_rust_call_status_arg: bool,
4144
}
4245

43-
/// Represents a repr(C) struct used in the FFI
46+
/// Represents a repr(C) struct
4447
#[derive(Debug, Default, Clone)]
4548
pub struct FfiStruct {
46-
pub(super) name: String,
47-
pub(super) fields: Vec<FfiField>,
49+
pub name: String,
50+
pub fields: Vec<FfiField>,
4851
}
4952

5053
/// Represents a field of an [FfiStruct]
5154
#[derive(Debug, Clone)]
5255
pub struct FfiField {
53-
pub(super) name: String,
54-
pub(super) type_: FfiType,
56+
pub name: String,
57+
pub ty: FfiType,
5558
}
5659

5760
/// Represents an argument to an FFI function.
5861
///
5962
/// Each argument has a name and a type.
6063
#[derive(Debug, Clone)]
6164
pub struct FfiArgument {
62-
pub(super) name: String,
63-
pub(super) type_: FfiType,
65+
pub name: String,
66+
pub ty: FfiType,
6467
}
6568

66-
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
69+
/// Represents an FFI type
70+
#[derive(Debug, Clone)]
6771
pub enum FfiType {
6872
// N.B. there are no booleans at this layer, since they cause problems for JNA.
6973
UInt8,
@@ -84,17 +88,15 @@ pub enum FfiType {
8488
/// A byte buffer allocated by rust, and owned by whoever currently holds it.
8589
/// If you've got one of these, you must either call the appropriate rust function to free it
8690
/// or pass it to someone that will.
87-
/// If the inner option is Some, it is the name of the external type. The bindings may need
88-
/// to use this name to import the correct RustBuffer for that type.
8991
RustBuffer(Option<ExternalFfiMetadata>),
9092
/// A borrowed reference to some raw bytes owned by foreign language code.
9193
/// The provider of this reference must keep it alive for the duration of the receiving call.
9294
ForeignBytes,
93-
/// Pointer to a callback function. The inner value which matches one of the callback
94-
/// definitions in [crate::ComponentInterface::ffi_definitions].
95-
Callback(String),
95+
/// Function pointer. The inner value is the name of one of the `FfiFunctionType` definitions
96+
/// in the IR.
97+
FunctionPointer(String),
9698
/// Pointer to a FFI struct (e.g. a VTable). The inner value matches one of the struct
97-
/// definitions in [crate::ComponentInterface::ffi_definitions].
99+
/// definitions in the IR.
98100
Struct(String),
99101
/// Opaque 64-bit handle
100102
///
@@ -108,3 +110,42 @@ pub enum FfiType {
108110
/// Opaque pointer
109111
VoidPointer,
110112
}
113+
114+
/// Set for RustBuffers for external types. These are usually defined in a different generated
115+
/// bindings module.
116+
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
117+
pub struct ExternalFfiMetadata {
118+
/// FIXME: only store one of these, we currently need to store them both for weird historical
119+
/// reasons.
120+
pub module_path: String,
121+
pub namespace: String,
122+
}
123+
124+
/// Ffi function to check a checksum for an item in the interface
125+
///
126+
/// Bindings generators should call each of these functions and check that they return the
127+
/// `checksum` value.
128+
#[derive(Debug, Clone)]
129+
pub struct ChecksumCheck {
130+
pub func: FfiFunctionRef,
131+
pub checksum: u16,
132+
}
133+
134+
/// Reference to an scaffolding function
135+
#[derive(Debug, Clone)]
136+
pub struct FfiFunctionRef {
137+
pub name: String,
138+
/// Used by C# generator to differentiate the free function and call it with void*
139+
/// instead of C# `SafeHandle` type. See <https://github.com/mozilla/uniffi-rs/pull/1488>.
140+
pub is_object_free_function: bool,
141+
}
142+
143+
impl FfiDefinition {
144+
pub fn name(&self) -> &str {
145+
match self {
146+
Self::Function(f) => &f.name,
147+
Self::FunctionType(f) => &f.name,
148+
Self::Struct(s) => &s.name,
149+
}
150+
}
151+
}

uniffi_bindgen/src/interface/ir/nodes/functions.rs

+41-27
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,58 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5+
use super::{FfiFunctionRef, FfiType, Literal, Type};
6+
57
/// Represents a standalone function.
68
///
79
/// Each `Function` corresponds to a standalone function in the rust module,
810
/// and has a corresponding standalone function in the foreign language bindings.
911
///
1012
/// In the FFI, this will be a standalone function with appropriately lowered types.
11-
#[derive(Debug, Clone, Checksum)]
13+
#[derive(Debug, Clone)]
1214
pub struct Function {
13-
pub(super) name: String,
14-
pub(super) module_path: String,
15-
pub(super) is_async: bool,
16-
pub(super) arguments: Vec<Argument>,
17-
pub(super) return_type: Option<Type>,
18-
// We don't include the FFIFunc in the hash calculation, because:
19-
// - it is entirely determined by the other fields,
20-
// so excluding it is safe.
21-
// - its `name` property includes a checksum derived from the very
22-
// hash value we're trying to calculate here, so excluding it
23-
// avoids a weird circular dependency in the calculation.
24-
#[checksum_ignore]
25-
pub(super) ffi_func: FfiFunction,
26-
#[checksum_ignore]
27-
pub(super) docstring: Option<String>,
28-
pub(super) throws: Option<Type>,
29-
pub(super) checksum_fn_name: String,
30-
// Force a checksum value, or we'll fallback to the trait.
31-
#[checksum_ignore]
32-
pub(super) checksum: Option<u16>,
15+
pub name: String,
16+
pub docstring: Option<String>,
17+
pub module_path: String,
18+
pub callable: Callable,
19+
}
20+
21+
/// Callable data, this is shared between functions, methods, and constructors.
22+
#[derive(Debug, Clone)]
23+
pub struct Callable {
24+
pub kind: CallableKind,
25+
pub async_data: Option<AsyncData>,
26+
pub arguments: Vec<Argument>,
27+
pub return_type: Option<Type>,
28+
pub throws_type: Option<Type>,
29+
pub ffi_func: FfiFunctionRef,
30+
}
31+
32+
#[derive(Debug, Clone)]
33+
pub enum CallableKind {
34+
Function,
35+
Method,
36+
VTableMethod,
37+
Constructor { primary: bool },
38+
}
39+
40+
#[derive(Debug, Clone)]
41+
pub struct AsyncData {
42+
pub ffi_rust_future_poll: FfiFunctionRef,
43+
pub ffi_rust_future_complete: FfiFunctionRef,
44+
pub ffi_rust_future_free: FfiFunctionRef,
45+
/// The FFI struct to pass to the completion function for callback interface methods
46+
pub foreign_future_result_type: FfiType,
3347
}
3448

3549
/// Represents an argument to a function/constructor/method call.
3650
///
3751
/// Each argument has a name and a type, along with some optional metadata.
38-
#[derive(Debug, Clone, Checksum)]
52+
#[derive(Debug, Clone)]
3953
pub struct Argument {
40-
pub(super) name: String,
41-
pub(super) type_: Type,
42-
pub(super) by_ref: bool,
43-
pub(super) optional: bool,
44-
pub(super) default: Option<Literal>,
54+
pub name: String,
55+
pub ty: Type,
56+
pub by_ref: bool,
57+
pub optional: bool,
58+
pub default: Option<Literal>,
4559
}

0 commit comments

Comments
 (0)