Skip to main content

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}