Wrap Rust types in Ruby objects
mainMagnus allows you to expose Rust structs and enums as Ruby objects. This enables Ruby to interact with Rust logic seamlessly. You can return these wrapped objects to Ruby or pass them back to Rust, where they are automatically unwrapped to native Rust references.
There are two primary ways to wrap a type:
- Use the
#[magnus::wrap]convenience macro. - Implement the
magnus::TypedDatatrait for more customization.
Handling Mutability
Because Ruby's GC manages the memory of the wrapped object, Magnus cannot bind functions using mutable references (&mut T). To allow mutation of fields within a wrapped struct, use the newtype pattern with RefCell.
use magnus::{function, method, prelude::*, Error, Ruby};
#[magnus::wrap(class = "Point")]
struct Point {
x: isize,
y: isize,
}
impl Point {
fn new(x: isize, y: isize) -> Self {
Self { x, y }
}
fn x(&self) -> isize {
self.x
}
fn y(&self) -> isize {
self.y
}
fn distance(&self, other: &Point) -> f64 {
(((other.x - self.x).pow(2) + (other.y - self.y).pow(2)) as f64).sqrt()
}
}
#[magnus::init]
fn init(ruby: &Ruby) -> Result<(), Error> {
let class = ruby.define_class("Point", ruby.class_object())?;
class.define_singleton_method("new", function!(Point::new, 2))?;
class.define_method("x", method!(Point::x, 0))?;
class.define_method("y", method!(Point::y, 0))?;
class.define_method("distance", method!(Point::distance, 1))?;
Ok(())
}