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
|
// For each Object definition, we assume the caller has provided an appropriately-shaped `struct T`
// with an `impl` for each method on the object. We create an `Arc<T>` for "safely" handing out
// references to these structs to foreign language code, and we provide a `pub extern "C"` function
// corresponding to each method.
//
// (Note that "safely" is in "scare quotes" - that's because we use functions on an `Arc` that
// that are inherently unsafe, but the code we generate is safe in practice.)
//
// If the caller's implementation of the struct does not match with the methods or types specified
// in the UDL, then the rust compiler will complain with a (hopefully at least somewhat helpful!)
// error message when processing this generated code.
{% if obj.uses_deprecated_threadsafe_attribute() %}
// We want to mark this as `deprecated` - long story short, the only way to
// sanely do this using `#[deprecated(..)]` is to generate a function with that
// attribute, then generate call to that function in the object constructors.
#[deprecated(
since = "0.11.0",
note = "The `[Threadsafe]` attribute on interfaces is now the default and its use is deprecated - you should upgrade \
`{{ obj.name() }}` to remove the `[ThreadSafe]` attribute. \
See https://github.com/mozilla/uniffi-rs/#thread-safety for more details"
)]
#[allow(non_snake_case)]
fn uniffi_note_threadsafe_deprecation_{{ obj.name() }}() {}
{% endif %}
// All Object structs must be `Sync + Send`. The generated scaffolding will fail to compile
// if they are not, but unfortunately it fails with an unactionably obscure error message.
// By asserting the requirement explicitly, we help Rust produce a more scrutable error message
// and thus help the user debug why the requirement isn't being met.
uniffi::deps::static_assertions::assert_impl_all!(r#{{ obj.name() }}: Sync, Send);
{% let ffi_free = obj.ffi_object_free() -%}
#[doc(hidden)]
#[no_mangle]
pub extern "C" fn {{ ffi_free.name() }}(ptr: *const std::os::raw::c_void, call_status: &mut uniffi::RustCallStatus) {
uniffi::call_with_output(call_status, || {
assert!(!ptr.is_null());
{#- turn it into an Arc and explicitly drop it. #}
drop(unsafe { std::sync::Arc::from_raw(ptr as *const r#{{ obj.name() }}) })
})
}
{%- for cons in obj.constructors() %}
#[doc(hidden)]
#[no_mangle]
pub extern "C" fn r#{{ cons.ffi_func().name() }}(
{%- call rs::arg_list_ffi_decl(cons.ffi_func()) %}) -> *const std::os::raw::c_void /* *const {{ obj.name() }} */ {
uniffi::deps::log::debug!("{{ cons.ffi_func().name() }}");
{% if obj.uses_deprecated_threadsafe_attribute() %}
uniffi_note_threadsafe_deprecation_{{ obj.name() }}();
{% endif %}
// If the constructor does not have the same signature as declared in the UDL, then
// this attempt to call it will fail with a (somewhat) helpful compiler error.
{% call rs::to_rs_constructor_call(obj, cons) %}
}
{%- endfor %}
{%- for meth in obj.methods() %}
#[doc(hidden)]
#[no_mangle]
#[allow(clippy::let_unit_value)] // Sometimes we generate code that binds `_retval` to `()`.
pub extern "C" fn r#{{ meth.ffi_func().name() }}(
{%- call rs::arg_list_ffi_decl(meth.ffi_func()) %}
) {% call rs::return_signature(meth) %} {
uniffi::deps::log::debug!("{{ meth.ffi_func().name() }}");
// If the method does not have the same signature as declared in the UDL, then
// this attempt to call it will fail with a (somewhat) helpful compiler error.
{% call rs::to_rs_method_call(obj, meth) %}
}
{% endfor %}
|