This document provides a detailed overview of the react-native-rs architecture and design decisions.
┌─────────────────────────────────────────────────────────────┐
│ React Native App │
├─────────────────────────────────────────────────────────────┤
│ TypeScript Bridge Layer │
│ • Type-safe command interface │
│ • Automatic serialization/deserialization │
│ • Error handling and panic recovery │
├─────────────────────────────────────────────────────────────┤
│ Platform Native Layer │
│ iOS (Objective-C++) │ Android (Java/JNI) │
│ • TurboModule integration │ • TurboModule support │
│ • Background thread exec │ • Native library load │
├─────────────────────────────────────────────────────────────┤
│ C++ Bridge Layer │
│ • Cross-platform C interface │
│ • Memory management │
│ • String marshaling │
├─────────────────────────────────────────────────────────────┤
│ Rust Core │
│ • High-performance computation │
│ • Async/await support │
│ • Parallel processing with Rayon │
│ • Comprehensive error handling │
│ • Structured logging │
└─────────────────────────────────────────────────────────────┘
// 1. TypeScript call
const result = await RustBridge.execute({
cmd: 'fibonacci',
params: { n: 40 }
});
// 2. Serialization
const cmdString = JSON.stringify(command);
// 3. Native module call (iOS/Android)
const resultString = await ReactNativeRs.execute(cmdString);
// 4. C++ bridge
const char* rust_execute(const char* cmd);
// 5. Rust execution
pub extern "C" fn rust_execute(raw_cmd: *const c_char) -> *const c_char
// 6. Command parsing and execution
let cmd = serde_json::from_str::<Command>(cmd_str)?;
let result = execute_cmd(cmd).await?;
// 7. Result serialization and return
serde_json::to_string(&result)?// Rust panic recovery
let exec_res = panic::catch_unwind(|| {
RUNTIME.block_on(async move {
execute_cmd(cmd).await
})
});
match exec_res {
Ok(res) => res,
Err(panic) => handle_panic(panic, cmd),
}Decision: Use a centralized command enum with tagged unions.
Rationale:
- Type safety across the Rust/TypeScript boundary
- Easy to extend with new operations
- Centralized error handling and logging
- Automatic TypeScript type generation
#[derive(Serialize, Deserialize, TS)]
#[serde(tag = "cmd", content = "params")]
pub enum Command {
Fibonacci(FibonacciInput),
HashData(HashDataInput),
// ... more commands
}Decision: Use a global Tokio runtime with multi-threading.
Rationale:
- Non-blocking operations for React Native UI
- Efficient resource utilization
- Platform-specific thread pool sizing
lazy_static! {
pub static ref RUNTIME: Arc<Runtime> =
Arc::new(Builder::new_multi_thread().enable_all().build().unwrap());
}Decision: Use owned strings with explicit memory management.
Rationale:
- Avoid memory leaks across FFI boundary
- Clear ownership semantics
- Safe string marshaling
pub extern "C" fn rust_free_string(ptr: *mut c_char) {
if !ptr.is_null() {
unsafe { let _ = CString::from_raw(ptr); };
}
}Decision: Automatic TypeScript type generation from Rust structs.
Rationale:
- Eliminates type mismatches at compile time
- Reduces maintenance overhead
- Ensures API consistency
#[derive(Serialize, Deserialize, TS)]
#[ts(export)]
pub struct FibonacciInput {
pub n: u32,
}- Rayon: Used for CPU-intensive operations like sorting and prime generation
- Thread Pool: Optimized for each platform (Android uses N-1 cores)
- Work Stealing: Efficient load balancing across cores
- Zero-Copy: Where possible, avoid unnecessary data copying
- String Interning: Efficient string handling across FFI
- Stack Allocation: Prefer stack over heap for small data structures
- LTO: Link-time optimization enabled for release builds
- Embed Bitcode: iOS compatibility for App Store submissions
- Target-Specific: Platform-specific optimizations
All Rust code is wrapped in panic::catch_unwind to prevent crashes:
let exec_res = panic::catch_unwind(|| {
// Rust execution code
});
match exec_res {
Ok(res) => res,
Err(panic) => handle_panic_gracefully(panic),
}- JSON schema validation at the Rust boundary
- Type-safe deserialization with
serde - Graceful error messages for invalid inputs
- Automatic cleanup of native resources
- Proper thread lifecycle management
- Memory leak prevention with RAII patterns
- TurboModule: Full new architecture support with fallback
- XCFramework: Universal binary for device and simulator
- CocoaPods: Seamless integration with existing projects
- JNI: Efficient Java-to-native communication
- CMake: Cross-compilation build system
- NDK: Multiple architecture support (ARM64, x86_64)
The build.sh script handles:
- Platform detection and configuration
- Target installation and compilation
- Library packaging and distribution
- Error handling and cleanup
- Cargo: Rust dependency management with workspaces
- npm/yarn: JavaScript package management
- CocoaPods: iOS native dependency management
- Gradle: Android build system integration
- Tracing: Hierarchical structured logging
- Log Collection: In-memory log storage for debugging
- Performance Metrics: Automatic timing and profiling
- Type Checking: Automatic verification of Rust/TS type sync
- Testing: Comprehensive unit and integration tests
- Linting: Code quality enforcement across all languages
The architecture is designed for easy extension:
- New Commands: Add to the
Commandenum and implement handler - New Platforms: Extend the build system and native modules
- New Features: Leverage the existing infrastructure
- Performance: Profile and optimize individual components
This architecture provides a solid foundation for high-performance React Native applications while maintaining type safety, error resilience, and cross-platform compatibility.