1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
{#
// For each Callback Interface definition, we assume that there is a corresponding trait defined in Rust client code.
// If the UDL callback interface and Rust trait's methods don't match, the Rust compiler will complain.
// We generate:
// * an init function to accept that `ForeignCallback` from the foreign language, and stores it.
// * a holder for a `ForeignCallback`, of type `uniffi::ForeignCallbackInternals`.
// * a proxy `struct` which implements the `trait` that the Callback Interface corresponds to. This
// is the object that client code interacts with.
// - for each method, arguments will be packed into a `RustBuffer` and sent over the `ForeignCallback` to be
// unpacked and called. The return value is packed into another `RustBuffer` and sent back to Rust.
// - a `Drop` `impl`, which tells the foreign language to forget about the real callback object.
#}
{% let trait_name = cbi.name() -%}
{% let trait_impl = format!("UniFFICallbackHandler{}", trait_name) %}
{% let foreign_callback_internals = format!("foreign_callback_{}_internals", trait_name)|upper -%}
// Register a foreign callback for getting across the FFI.
#[doc(hidden)]
static {{ foreign_callback_internals }}: uniffi::ForeignCallbackInternals = uniffi::ForeignCallbackInternals::new();
#[doc(hidden)]
#[no_mangle]
pub extern "C" fn {{ cbi.ffi_init_callback().name() }}(callback: uniffi::ForeignCallback, _: &mut uniffi::RustCallStatus) {
{{ foreign_callback_internals }}.set_callback(callback);
// The call status should be initialized to CALL_SUCCESS, so no need to modify it.
}
// Make an implementation which will shell out to the foreign language.
#[doc(hidden)]
#[derive(Debug)]
struct {{ trait_impl }} {
handle: u64
}
impl {{ trait_impl }} {
fn new(handle: u64) -> Self {
Self { handle }
}
}
impl Drop for {{ trait_impl }} {
fn drop(&mut self) {
{{ foreign_callback_internals }}.invoke_callback::<(), crate::UniFfiTag>(
self.handle, uniffi::IDX_CALLBACK_FREE, Default::default()
)
}
}
uniffi::deps::static_assertions::assert_impl_all!({{ trait_impl }}: Send);
impl r#{{ trait_name }} for {{ trait_impl }} {
{%- for meth in cbi.methods() %}
{#- Method declaration #}
fn r#{{ meth.name() -}}
({% call rs::arg_list_decl_with_prefix("&self", meth) %})
{%- match (meth.return_type(), meth.throws_type()) %}
{%- when (Some(return_type), None) %} -> {{ return_type.borrow()|type_rs }}
{%- when (Some(return_type), Some(err)) %} -> ::std::result::Result<{{ return_type.borrow()|type_rs }}, {{ err|type_rs }}>
{%- when (None, Some(err)) %} -> ::std::result::Result<(), {{ err|type_rs }}>
{% else -%}
{%- endmatch -%} {
{#- Method body #}
{#- Packing args into a RustBuffer #}
{% if meth.arguments().len() == 0 -%}
let args_buf = Vec::new();
{% else -%}
let mut args_buf = Vec::new();
{% endif -%}
{%- for arg in meth.arguments() %}
{{ arg.as_type().borrow()|ffi_trait("Lower") }}::write(r#{{ arg.name() }}, &mut args_buf);
{%- endfor -%}
let args_rbuf = uniffi::RustBuffer::from_vec(args_buf);
{#- Calling into foreign code. #}
{{ foreign_callback_internals }}.invoke_callback::<{{ meth|return_type }}, crate::UniFfiTag>(self.handle, {{ loop.index }}, args_rbuf)
}
{%- endfor %}
}
::uniffi::scaffolding_ffi_converter_callback_interface!(r#{{ trait_name }}, {{ trait_impl }});
|