# Overview In order for `libsignal` to be used from Java, Swift, and TypeScript, the Rust code must be exposed, or "bridged" to those languages with compatible entry points. That's the purpose of the crates in this directory. # Bridged function definitions [`libsignal-bridge`](./shared/) defines functions that are callable from Java, Swift, and TypeScript. These definitions make use of the `#[bridge_fn]` and `#[bridge_io]` macros to provide the language-specific glue code that makes the functions visible from other languages. [`libsignal-bridge-macros`](./shared/macros/) is a [proc-macro] crate that defines the `#[bridge_fn]` and `#[bridge_io]` macros. Attaching one of these macros to a function definition causes the macro to emit `#[cfg]`-guarded entry point for each supported language. These entry points, before calling the actual annotated Rust function, perform functionality like language-specific parsing and [conversion](#type-conversions) of input arguments, panic trapping, and spawning of tasks for `async` functions. They also handle return value conversion and language-specific error handling. The macros attach any needed code to the bridged functions to enable language-specific mechanisms ([more below](#bridged-function-collection)) to identify and collect the entry points and make them callable. # Bridged types The [`libsignal-bridge-types`](./shared/types/) crate defines traits and impls that reduce the amount of boilerplate code required to write bridged functions. These generally fall into three categories: 1. type conversions 2. runtime support 3. language utilities ## Type conversions Input arguments are converted from their language-native form into Rust types using the `ArgTypeInfo` traits defined for each language in the per-language submodule ([`libsignal_bridge_types::ffi`], [`libsignal_bridge_types::jni`], and [`libsignal_bridge_types::node`]). To make a type usable as an argument to a function annotated with `#[bridge_fn]` or `#[bridge_io]`, the three `ArgTypeInfo` traits need to be implemented for that type, either directly or indirectly. The type also needs to be added to the `ffi_arg_type`, `jni_arg_type`, and `node_arg_type` macros. Returned types are treated similarly, except that the language-specific traits are named `ResultTypeInfo`, and the macros are `ffi_result_type` and similar. ## Runtime support Some Rust features aren't exposed directly to other languages, but instead require some runtime support. As an example, when `#[bridge_fn]` is attached to an `async` function, the exposed entry point takes as an additional argument the async runtime to be used. `libsignal_bridge_types` defines traits that support this. ## Language utilities Some languages require additional code to support bridged functions. The `jni` module, for example, defines a function to be invoked when the library is loaded that caches a class loader for use during later return type conversions. The `node` module defines a function that registers a sequence of annotated functions with a JavaScript runtime. # Bridged function collection To make the function entry points generated by the `#[bridge_fn]` and `#[bridge_io]` macros visible to the target languages, the functions must be collected and exposed. The mechanism for this is language-specific, but relies on annotations attached to the entry points. For Swift, and Java, [`cbindgen`] is used to process the [`libsignal-ffi`](./ffi/) and [`libsignal-jni`](./jni/) crates to produce a list of function prototypes. For Java, these prototypes are munged by the [`gen_java_decl.py`](./jni/bin/gen_java_decl.py) and interpolated into the [`Native.java.in`](./jni/bin/Native.java.in) file to produce a self-contained class definition. For Swift, the `cbindgen` output is saved directly to a C-style `.h` file that the Swift toolchain can consume. For TypeScript, the [`libsignal-node`] crate is expanded and processed by [`gen_ts_decl.py`](./node/bin/gen_ts_decl.py) and the output is interpolated into [`Native.ts.in`](./node/bin/Native.ts.in). The output, however, only declares the function signatures; to make them accessible to the JavaScript runtime, additional machinery is used. This takes the form of `#[linkme]` annotations on to the generated entry points; the [`linkme`] crate is used to collect all these entry points at link time for explicit registration at runtime. [`libsignal_bridge_types::ffi`]: ./shared/ffi/ [`libsignal_bridge_types::jni`]: ./shared/jni/ [`libsignal_bridge_types::node`]: ./shared/node/ [`libsignal-node`]: ./shared/node/ [proc-macro]: https://doc.rust-lang.org/reference/procedural-macros.html [`linkme`]: https://crates.io/crates/linkme [`cbindgen`]: https://crates.io/crates/cbindgen