Frequently Asked Questions
Answers to common questions about building Ruby extensions with Rust.
General
Q: When should I use Rust for a Ruby extension?
A: Use Rust for CPU-bound, memory-intensive, or security-sensitive tasks, or for wrapping existing Rust libraries. See Development Approaches.
Q: Is Rust harder to learn than C for writing gems?
A: Rust has a steeper initial learning curve due to ownership rules, but its compiler prevents bugs common in C extensions.
Q: Will my code be faster?
A: Rust extensions can be 10-100x faster for CPU-intensive tasks. However, FFI overhead can make simple operations slower. Always profile first. See Performance.
Q: Will a Rust extension work with Rails?
A: Yes. A Rust-based gem functions like any other gem and can be used within a Rails application.
Technical
Q: How do I debug my extension?
A: Compile with debug symbols and use gdb or lldb. See Debugging.
Q: How do I distribute my gem to users?
A: Ship pre-compiled ("fat") gems for common platforms to avoid requiring users to install Rust. See Deployment & Distribution.
Q: How do I handle panics?
A: Avoid panics; they crash Ruby. Functions should return Result<T, magnus::Error> to convert Rust errors into Ruby exceptions. See Error Handling.
Q: Why is my extension slower than I expected?
A: There are common causes:
1. Too many conversions:
use magnus::{Error, RArray, TryConvert};
// Bad: Converts entire array upfront
fn sum(numbers: Vec<i64>) -> i64 {
numbers.iter().sum()
}
// Good: Iterates without conversion
fn sum_good(array: RArray) -> Result<i64, Error> {
let mut total = 0;
for item in array.each() {
total += i64::try_convert(item?)?;
}
Ok(total)
}
2. Not releasing the GVL:
fn release_gvl_example(data: &[u8]) {
// Release GVL for operations > 100ms
if data.len() > 1_000_000 {
// Use rb_thread_call_without_gvl
}
}
3. Excessive allocations:
fn excessive_allocations() {
// Bad: Allocates repeatedly
for i in 0..1000 {
let mut vec: Vec<i32> = Vec::new();
// ...
}
// Good: Reuse allocation
let mut vec: Vec<i32> = Vec::with_capacity(1000);
for i in 0..1000 {
vec.clear();
// ...
}
}
Troubleshooting
Q: I'm getting "undefined symbol" errors.
A: Ensure your Rust function is marked #[magnus::init] or #[no_mangle] pub extern "C" fn Init_my_gem(), crate-type is ["cdylib"], and names match extconf.rb.
Q: The build is failing with a "libclang not found" error.
A: rb-sys uses bindgen, which requires libclang. Add gem "libclang" to your Gemfile, or install libclang via your system package manager (e.g., brew install llvm, apt-get install libclang-dev).