expo_modules_rs/lib.rs
1//! # expo-modules-rs
2//!
3//! Rust SDK for writing Expo native modules that integrate directly
4//! with the JavaScript Interface (JSI) runtime.
5//!
6//! This crate provides:
7//! - The `ExpoModule` trait and `ModuleBuilder` for defining modules
8//! - `JsValue` types and conversion traits (`FromJsValue`, `IntoJsValue`)
9//! - The cxx bridge to the JSI C++ layer
10//! - The `#[expo_module]` and `#[derive(ExpoRecord)]` proc macros
11//!
12//! ## Architecture
13//!
14//! ```text
15//! +---------------+ +----------------+ +----------------+
16//! | JavaScript |---->| JSI (C++) |---->| Rust Module |
17//! | (Hermes) |<----| jsi_shim.cpp |<----| (your crate) |
18//! +---------------+ +----------------+ +----------------+
19//! | | |
20//! JS calls cxx bridge ExpoModule
21//! module.fn() FfiValue trait impl
22//! ```
23//!
24//! ## Quick Start
25//!
26//! ```rust,ignore
27//! use expo_modules_rs::prelude::*;
28//!
29//! struct MathModule;
30//!
31//! #[expo_module("RustMath")]
32//! impl MathModule {
33//! #[constant]
34//! const PI: f64 = std::f64::consts::PI;
35//!
36//! fn add(a: f64, b: f64) -> f64 {
37//! a + b
38//! }
39//! }
40//! ```
41
42pub mod bridge;
43pub mod module;
44pub mod value;
45
46/// Prelude module - import everything needed for module development.
47pub mod prelude {
48 pub use crate::module::{ExpoModule, ModuleBuilder, ModuleDefinition, ModuleRegistry};
49 pub use crate::value::{
50 ExpoError, FromJsValue, IntoJsValue, JsArray, JsObject, JsValue, PromiseHandle, Runtime,
51 };
52 pub use expo_module_macro::{expo_module, ExpoRecord};
53}
54
55/// C entry point called from the native side (Android JNI or iOS ObjC++)
56/// to initialize Rust modules on the JSI runtime.
57///
58/// The `get_registry` closure must return a `ModuleRegistry` populated
59/// with all modules to install.
60///
61/// # Safety
62/// The runtime_ptr must be a valid pointer to a `jsi::Runtime`.
63pub unsafe fn install_modules(
64 runtime_ptr: *mut std::ffi::c_void,
65 get_registry: impl FnOnce() -> module::ModuleRegistry,
66) {
67 if runtime_ptr.is_null() {
68 eprintln!("[ExpoRust] ERROR: runtime_ptr is null!");
69 return;
70 }
71
72 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
73 let rt = value::Runtime {
74 handle: bridge::ffi::RuntimeHandle {
75 ptr: runtime_ptr as *mut u8,
76 },
77 };
78
79 let registry = get_registry();
80 registry.install(&rt);
81 }));
82
83 if let Err(e) = result {
84 eprintln!("[ExpoRust] PANIC during install: {:?}", e);
85 }
86}