#[derive(TypedData)]
{
// Attributes available to this derive:
#[magnus]
}
Expand description
Derives TypedData
, allowing the type to be passed to Ruby automatically
wrapped as a Ruby object.
For simple cases, see wrap
.
§Attributes
The #[magnus(...)]
attribute can be set with the following values:
class = "..."
- required, sets the Ruby class to wrap the Rust type. Supports module paths, e.g.Foo::Bar::Baz
.name = "..."
- debug name for the type, must be unique. Defaults to the class name.free_immediately
- Drop the Rust type as soon as the Ruby object has been garbage collected. This is only safe to set if the type’s [Drop
] andDataTypeFunctions::free
implementations do not call Ruby.mark
- Enable Ruby calling theDataTypeFunctions::mark
function.size
- Enable Ruby calling theDataTypeFunctions::size
function.compact
- Enable Ruby calling theDataTypeFunctions::compact
function.wb_protected
- Enable thewb_protected
flag.frozen_shareable
- Enable thefrozen_shareable
flag.unsafe_generics
- The derived implementation ofTypedData
is not guaranteed to be correct for types with generics. If you are sure it is for your type this attribute can be used to override the compile time error usually generated for types with generics.
§Field Attributes
The #[magnus(...)]
attribute can be set on struct fields with the
following values:
opaque_attr_reader
- For a Ruby value wrapped inOpaque
, creates a accessor method that returns the unwrapped Ruby value.
§Variant Attributes
The #[magnus(...)]
attribute can be set on enum variants with the
following values:
class = "..."
- sets the Ruby class to wrap the variant. Supports module paths, e.g.Foo::Bar::Baz
.
§Examples
use magnus::{DataTypeFunctions, TypedData};
#[derive(DataTypeFunctions, TypedData)]
#[magnus(class = "RbPoint", size, free_immediately)]
struct Point {
x: isize,
y: isize,
}
// the `Point` struct is automatically wrapped in a Ruby `RbPoint` object
// when returned to Ruby.
fn point(x: isize, y: isize) -> Point {
Point { x, y }
}
// Ruby `RbPoint` objects are automatically unwrapped to references to the
// `Point` structs they are wrapping when this function is called from Ruby.
fn distance(a: &Point, b: &Point) -> f64 {
(((b.x - a.x).pow(2) + (b.y - a.y).pow(2)) as f64).sqrt()
}
#[magnus::init]
fn init() {
magnus::define_global_function("point", magnus::function!(point, 2));
magnus::define_global_function("distance", magnus::function!(distance, 2));
}
With subclasses for enum variants:
use magnus::{class, define_class};
#[magnus::wrap(class = "Shape")]
enum Shape {
#[magnus(class = "Circle")]
Circle { r: f64 },
#[magnus(class = "Rectangle")]
Rectangle { x: f64, y: f64 },
}
#[magnus::init]
fn init() -> Result<(), magnus::Error> {
let shape = define_class("Shape", class::object())?;
define_class("Circle", shape)?;
define_class("Rectangle", shape)?;
Ok(())
}
Defining a custom DataType
function:
use std::mem::size_of_val;
use magnus::{DataTypeFunctions, TypedData};
#[derive(TypedData)]
#[magnus(class = "Name", size, free_immediately)]
struct Name {
first: String,
last: String,
}
impl DataTypeFunctions for Name {
fn size(&self) -> usize {
size_of_val(&self.first) + size_of_val(&self.last)
}
}
A struct containing Ruby values.
use magnus::{
class, define_class, function, gc, method, prelude::*, typed_data::Obj, value::Opaque,
DataTypeFunctions, TypedData,
};
#[derive(TypedData)]
#[magnus(class = "Line", free_immediately, mark)]
struct Line {
#[magnus(opaque_attr_reader)]
start: Opaque<Obj<Point>>,
#[magnus(opaque_attr_reader)]
end: Opaque<Obj<Point>>,
}
impl Line {
fn new(start: Obj<Point>, end: Obj<Point>) -> Self {
Self {
start: start.into(),
end: end.into(),
}
}
fn length(&self) -> f64 {
let start = self.start();
let end = self.end();
(((end.x - start.x).pow(2) + (end.y - start.y).pow(2)) as f64).sqrt()
}
}
impl DataTypeFunctions for Line {
fn mark(&self, marker: &gc::Marker) {
marker.mark(self.start);
marker.mark(self.end);
}
}
#[magnus::init]
fn init() -> Result<(), magnus::Error> {
let line = define_class("Line", class::object())?;
line.define_singleton_method("new", function!(Line::new, 2))?;
line.define_method("length", method!(Line::length, 0))?;
Ok(())
}