NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
crates.io · #4446 most downloaded on crates.io
Derive and proc macros for magnus
Last release 9 days ago
29 Sep 2026
Release timing varies
gaps range from 5 weeks to 2.1 years
Nearly every release is documented
notes for 9 of 9 stable releases
Nothing withdrawn
no release was ever pulled
5 years old
9 releases · first in 2022
One column per quarter.
Magnus 0.9.1 is a patch release, with 1 bug fix.
Magnus 0.9.1 is a patch release, with 1 bug fix.
Bumps the dependency for the quote crate in magnus-macros to 1.0.37 or later, as magnus-macros depends on CString support that was added in 1.0.37. Thanks to @y-yagi for this fix.
See the 0.9.0 release for what's new in 0.9.
quote dependency to 1.0.37 in magnus-macros for CString support.The 'old-api' feature, which previously disabled deprecation warnings for the old api (largely the ability to create Ruby objects with associated func…
Magnus 0.9.0 adds a handful of features and fixes, otherwise it is largely compatible with 0.8.
Magnus is a Rust library providing a high-level easy-to-use interface to the C API of the Ruby programming language. Magnus lets you write Ruby extension libraries (or 'gems') in Rust, or embed Ruby in your Rust program.
The debug module implements functions from Ruby's debug.h header, including Ruby::profile_frames, Ruby::debug_inspector_open, Ruby::tracepoint_new, and Ruby::postponed_job_preregister.
Conversions for C strings with Ruby::str_from_c_str, RString::to_c_string, and implementations of IntoRString for &CStr, IntoValue for &CStr, and TryConvert for CString.
RString::modify_expand to grow the capacity of a Ruby string.
RTypedData::as_ptr/typed_data::Obj::as_ptr to get the raw pointer to Rust data that has been wrapped as a Ruby object.
Minimum supported Rust version is now 1.85.
The supported Ruby versions are now 4.0, 3.4, 3.3, and 3.2. Magnus will compile with Ruby 3.1, but tests are no longer run for Ruby 3.1. Small patches will be accepted for Ruby 3.1 compatibility. Magnus will no longer compile with Ruby 2.7 and 3.0.
As of the time of this release Magnus works with the unreleased Ruby 4.1. It is possible that changes in this unreleased version of Ruby may break compatibility before the release of 4.1.
Magnus is no longer tested on macOS Intel, though it should still compile and patches will be accepted for macOS Intel compatibility.
The 'old-api' feature, which previously disabled deprecation warnings for the old api (largely the ability to create Ruby objects with associated functions, like RArray::new) now enables/disables the old api, with deprecation warnings no longer optional. The old api will be removed entirely in the next (0.10.0) version of Magnus.
Ruby::define_global_function now returns Result<(), Error> rather than ().
RArray::each, has been removed, use ary.into_iter() or ary.enumeratorize(\"each\", ()) instead.
RStruct::get and RStruct::set have been removed. While they had a small performance benefit they posed a compatibility hazard with future versions of Ruby. They should be easily swapped for the directly compatible RStruct::aref and RStruct::aset.
The data_type_builder! and r_string! macros have been deprecated in favour of functions taking &'static CStr now that C-string literals are available in Rust. See the changelog for more details and other deprecations.
See the changelog for all the changes.
@ankane for support for conversions to/from CString and &CStr
@gjtorikian for a fix for compiling with the musl C standard library on 32-bit systems
@pboling for a fix for the future Ruby 4.1 release
Ruby::profile_frames to collect a lightweight backtrace for profiling.Thread::profile_frames to collect a lightweight backtrace for profiling a
specific thread.Ruby::debug_inspector_open to acquire a DebugInspector struct that gives
access to the current frame's self, class, binding, and instruction sequence.Ruby::tracepoint_new and TracePoint to access Ruby's TracePoint api.Ruby::postponed_job_preregister and PostponedJobHandle::trigger to
register and trigger postponed jobs that can be triggered from non-Ruby
threads/without the GVL to be run later from a Ruby thread with the GVL.Ruby::str_from_c_str, RString::to_c_string,
and implementations of IntoRString for &CStr, IntoValue for &CStr, and
TryConvert for CString.RString::modify_expand to grow the capacity of a Ruby string.RTypedData::as_ptr/typed_data::Obj::as_ptr to get the raw pointer to Rust
data wrapped as a Ruby object.Ruby::define_global_function now returns Result<(), Error> rather than ().Ruby::get no longer caches the GVL state of the current thread.data_type_builder! macro. Please use
DataTypeBuilder::<Example>::new(c\"example\") instead.r_string! macro. Please use Ruby::utf8_str_new_static(c\"example\")
instead.gc::register_mark_object. Please use Ruby::gc_register_mark_object instead.gc::register_address. Please use Ruby::gc_register_address instead.gc::unregister_address. Please use Ruby::gc_unregister_address instead.IntoValue::into_value_unchecked, IntoRString::into_r_string_unchecked,
IntoSymbol::into_symbol_unchecked, and IntoId::into_id_unchecked. Please
use the _with variant passing &Ruby::get_unchecked(), e.g.
"example".into_r_string_with(&Ruby::get_unchecked()).RArray::each, use ary.into_iter() or ary.enumeratorize(\"each\", ())
instead.RStruct::get/RStruct::set, use RStruct::aref/RStruct::aset instead.arm-linux-musl).The old-api feature introduced in 0.7.0 is no longer a default feature, so functions marked as part of the old API will be deprecated by default. Othe…
Magnus 0.8.0 adds a handful of features and fixes. The old-api feature introduced in 0.7.0 is no longer a default feature, so functions marked as part of the old API will be deprecated by default. Otherwise it is largely compatible with 0.7.
Magnus is a Rust library providing a high-level easy-to-use interface to the C API of the Ruby programming language. Magnus lets you write Ruby extension libraries (or 'gems') in Rust, or embed Ruby in your Rust program.
fatal exception raised when a Rust function bound to Ruby panics can no longer be caught with rescue Exception.TryConvertOwned for (T, ...) so that T must be TryConvertOwned.The minimum supported Rust version in now 1.65.
Magnus 0.5 and earlier would allow you to create Ruby objects with associated functions, like RArray::new. In Magnus 0.6 a new set of APIs for creating Ruby objects was added, as methods on a Ruby handle that can only be obtained on a Ruby thread. The older associated functions API is now marked as deprecated by default. The old-api feature can be enabled to disable deprecation warnings for the old API. In a future version of Magnus will remove this feature.
The FString type has been removed as it can not safely uphold the promise it was making. Either due to Ruby's apis changing or a misinterpretation of old documentation it had been designed assuming interned strings (aka 'fstrings') would not be garbage collected, which is not the case.
Conversions between Ruby's Time and Rust's SystemTime now preserve nanosecond precision.
RString::to_string will now use a Ruby utf-8 validation api that caches the results of the validity check. This will greatly improve performance in the case a string is already known to be utf-8, but may slightly reduce performance when not known.
Ruby::time_nano_new, Ruby::time_timespec_new, and Time::timespec.chrono feature can be enabled to allow automatic conversions between chrono::DateTime<Utc> and chrono::DateTime<FixedOffset> and Ruby Time objects.typed_data::Writebarrier::writebarrier and writebarrier_unprotect.NonZero types, i128/u128, and BTreeMap.Ruby::io_extract_modeenc.Upgrading from Magnus 0.6 or 0.7 should be straightforward. If upgrading from 0.5 or earlier, it's recommended to upgrade to 0.6 first.
FromIterator for RArray and RHash are hidden behind the old-api feature (which will be removed in a future version of Magnus). Use Ruby::ary_from_iter and Ruby::hash_from_iter rather than RArray/Rhash::from_iter or collect::<RArray>()/collect::<RHash>().
See the changelog for all the changes.
@ankane for implementing TryConvert for NonZero types, i128/u128 support, and some additional improvements.
@emwalker for the chrono feature.
@erickguan for improvements to docs, some fixes, and IO features including Ruby::io_extract_modeenc.
@ianks and @sandbergja for other fixes.
@yaroslav for a detailed issue report that lead to an improvement.
Ruby::time_nano_new, Ruby::time_timespec_new, and Time::timespec.chrono feature can be enabled to allow automatic conversions
between chrono::DateTime<Utc> and chrono::DateTime<FixedOffset> and Ruby
Time objects.typed_data::Writebarrier::writebarrier and writebarrier_unprotect.TryConvert for NonZero types.io module available with io feature, supporting io_extract_modeenc,
OpenFlags, FMode, and IoEncoding.Ruby::io_extract_modeenc, a safe wrapper around rb_io_extract_modeenc,
allowing structured extraction of open flags, mode flags, and IO encoding
metadata.OpenFlags struct, which wraps Ruby's O_ open flags
(e.g. O_RDONLY, O_CREAT) in a convenient bitflag-like interface.FMode struct, representing FMODE_ flags used internally by Ruby to
represent IO modes (READ, WRITE, BINARY_MODE, etc.).IoEncoding, a safe Rust struct for temporarily owning and
inspecting rb_io_encoding, including safe accessors for
internal/external encoding and encoding options.i128/u128.to_i128/to_u128 for Fixnum/Bignum/Integer.Ruby::integer_from_i128 & Ruby::integer_from_u128.RHash::to_btree_map and automatic conversion from Hash to BTreeMap.Time and Rust's SystemTime now preserve
nanosecond precision.RString::to_string will now use a Ruby utf-8 validation api that caches the
results of the validity check. This will greatly improve performance in the
case a string is already known to be utf-8, but may slightly reduce
performance when not known.RString::to_interned_str now returns an RString rather than an FString.thread_fd_close as it will be a no-op as of Ruby 3.5FString as it can not safely uphold the promise it was making. Either due
to Ruby's apis changing or a misinterpretation of old documentation it had
been designed assuming interned strings (aka fstrings) would not be garbage
collected, which is not the case.RString::as_interned_str as its only purpose was to return an FString.fatal exception raised when a Rust function bound to Ruby panics can no
longer be caught with rescue Exception.TryConvertOwned for (T, ...) so that T must be
TryConvertOwned.Ruby types are no longer Send or Sync. These types can be made Send & Sync with the deprecated-send-sync-value feature. This feature is meant to ease…
value::Opaque can be used to wrap a Ruby type to make it Send + Sync.value::Lazy lazily initialises a Ruby value so it can be assigned to a
static.value::OpaqueId is a Send + Sync version of value::Id.value::LazyId is an Id with a const constructor so can be assigned to a
static and derefs to OpaqueId.error::OpaqueError is a Send + Sync version of Error.#[magnus(opaque_attr_reader)] attribute can be set on Opaque wrapped
fields of a struct when deriving TypedData to generate a method to return
the inner value.Ruby::init function to initialise Ruby when embedding Ruby in Rust that
runs a function with Ruby initialised, passing &Ruby.rb_assert!() macro to assert a Ruby expression evaluates to a truthy value.Class::undef_default_alloc_func to remove a class' allocator function only
if it is Ruby's default allocator function.Class::obj_alloc and Class::define_alloc_func for allocating an object
without calling initialize, and for defining an allocator function.RTypedData::wrap_as & typed_data::Obj<T>::wrap_as can be used to
dynamically set the class when wrapping Rust data in a Ruby object. This can
be used to allow wrapped data to be subclassed in Ruby.Exception::exception_class returns the class of an exception as an
ExceptionClass.kwargs!() macro and KwArgs type can be used to pass keyword arguments
to ReprValue::funcall, et al.bytes-crate feature has been renamed to bytes.rb-sys-interop feature has been renamed to rb-sys.Send or Sync. These types can be made Send &
Sync with the deprecated-send-sync-value feature. This feature is meant
to ease upgrading and will be removed with the next release.Value's methods moved to the ReprValue trait.typed_data::Obj<T> derefs to T so now T's methods can be called
directly on typed_data::Obj<T>.ReprValue and TryConvert added to magnus::prelude.typed_data::Cmp, typed_data::Dup and typed_data::Inspect traits to help
with implementing #<=>, #dup & #clone, and #inspect methods for
wrapped structs.Sync to enable frozen_shareable flag.TypedData::class and TypedData::class_for now take a &Ruby argument.DataTypeFunctions::mark and DataTypeFunctions::compact now take
&gc::Marker and &gc::Compactor arguments respectively.#[magnus::init] optionally takes a &Ruby
argument.method!() and function!() optionally
take &Ruby as a first argument.embed::init derefs to Ruby.DataTypeBuilder::new/DataType::builder now take their name argument
as a 'static CStr (see the magnus::data_type_builder! macro to construct
a DataTypeBuilder with a 'static CStr name).DataTypeBuilder are now const, so DataType can be
constructed in a const context and be assigned to a static.#[wrap] and #[derive(TypedData)] macros now support setting the
#[magnus(unsafe_generics)] attribute to allow deriving TypedData for
types with generics. The derived implementation is not guaranteed to be
correct.typed_data::Obj::get as it is made redundant by the Deref implementation
for typed_data::Obj.QTRUE, QFALSE, and QNIL constants. Please use value::qtrue(),
value::qfalse(), and value::qnil().Class::undef_alloc_func. Please use Class::undef_default_alloc_func.Value::try_convert, prefer TryConvert::try_convert or T::try_convert.Binding. To call methods on Ruby's binding, use ReprValue::funcall on a
Value know to be an instance of Ruby's Binding class.gc::{mark, mark_slice, mark_movable, location}, instead use
gc::Marker::{mark, mark_slice, mark_movable} and Compactor::location.RStruct::as_slice.RClass, import magnus::Class trait or
magnus::prelude::*.Into<Value>/From<T> for Value implementations, use IntoValue.Default implementations for Value, RClass, and ExceptionClass.Error can no longer be directly constructed, must use Error::new or
Error::from/Exception::into.RString::append (use RString::buf_append).Error::runtime_error (use Error::new(exception::runtime_error(), msg)).RFloat::from_value now returns None when value is a Flonum.scan_args::get_kwargs error/segfault when leading optional args were not provided, due to trying to convert the type of the missing value.
scan_args::get_kwargs error/segfault when leading optional args were not
provided, due to trying to convert the type of the missing value.impl TryConvert for Exception and ExceptionClass.
Value::funcall_with_block.TryConvert for Exception and ExceptionClass.Class trait (implemented for RClass and ExceptionClass).define_error and Module::define_error helpers for defining an Exception
Class.RTypedData::wrap and RTypedData::get inherent methods for wrapping Rust
types in Ruby objects.Send.Value::block_call. Use Proc::from_fn + Value::funcall_with_block
for closures that capture variables.Proc::new only accepts a function pointer, use Proc::from_fn for closures
that capture variables.ExceptionClass::default() now returns StandardError rather than
RuntimeError.TryConvert now takes Value by value (rather than a reference).DataTypeBuilder::free_immediatly (use free_immediately).free_immediatly attribute in wrap macro (use free_immediately).free_immediatly in magnus attribute of derive(TypedData) macro
(use free_immediately).String::encode_utf8, use r_string.conv_enc(RbEncoding::utf8()) instead.Value::leak, use gc::register_mark_object instead.define_global_variable (use define_variable).Error to raise an exception.Flonum support disabled for Ruby built with USE_FLONUM=0 (e.g. 32 bit
systems).free_immediatly (to free_immediately) in the
DataTypeBuilder struct, and wrap and derive(TypedData) macros.printf-style format strings no longer interpreted in error messages when
automatically raised as Ruby exceptions.RString::new_shared and RString::new_frozen.
RString::new_shared and RString::new_frozen.encoding module, including encoding::Index and RbEncoding types.RString::enc_coderange and related methods.RString::codepoints and RString::char_bytes iterators over string
contents.RArray: dup, concat, plus, delete,
delete_at, resize, reverse, rotate, and sort.RString: enc_new, len, length, and is_empty.RHash gains the methods delete and clear.require, current_receiver, call_super, and define_global_const
functions.Object::singleton_class and Object::extend_object.Proc::new, Proc::arity, and Proc::is_lambda.superclass and name methods for RClass.scan_args::check_arity.Module: include_module, prepend_module, const_set,
ancestors, define_attr, and define_alias.rb-sys-interop feature to use low level bindings from rb-sys, and rb_sys
module to expose functions for working with rb-sys.gc::register_mark_object, gc::register_address,
gc::unregister_address, gc::count, gc::stat, and gc::all_stats.Error::iter_break.StaticSymbol::check and Id::check to check if a symbol exists.RArray::cat, RArray::from_slice, and gc::mark_slice will accept a
slice of any Ruby type as an argument, rather than only a slice of Value.
This may change type inference rules such that things like
RArray::from_slice(&[1.into()]) will no longer work. Use
RArray::from_slice(&[Value::from(1)]) instead.gc::location will accept any Ruby type as an argument.BoxValue can hold any Ruby type, not just Value.RHash::foreach will now be
automatically converted from Value to Rust types.Module::define_method, Module::define_private_method,
Module::define_protected_method, RModule::define_singleton_method, and
Object::define_singleton_method all return Result<(), Error> rather than
() as they may fail in the unusual case that the receiver is frozen.String::encode_utf8, use r_string.conv_enc(RbEncoding::utf8()) instead.Value::leak, use gc::register_mark_object instead.define_global_variable (use define_variable) to better match Ruby C API
naming.Exception::backtrace, use ex.funcall("backtrace", ()) instead.error::protect removed as it should not be needed when using Magnus. For
use with rb-sys enable the rb-sys-interop feature and use
magnus::rb_sys::protect.Qfalse::new, Qnil::new, Qtrue::new, Qundef::new (use
QFALSE/QNIL/QTRUE/QUNDEF).Error with a specific Ruby type. E.g.
Error::type_error("..."), use Error::new(exception::type_error(), "...").StaticSymbol from a &str with characters outside the ASCII
range.DataTypeFunctions will abort the
process to avoid undefined behaviour.RHash::foreach won't result in undefined
behaviour.Functions in class, module, and error modules to access built-in classes/modules.
class, module, and error modules to access built-in
classes/modules.RArray::len, RArray::includes, RArray::join, RArray::is_shared,
RArray::replace, and RArray::subseq.From<&str> and From<String> for RString.Range.Class::new and Module::new for creating anonymous classes/modules.r_string! macro to create Ruby string from a str literal.Value::equal and Value::eql for object equality.Value::respond_to and Value::check_funcall for conditionally calling Ruby
methods only when they are defined.scan_args and get_kwargs for complex argument parsing.Qundef::to_value now marked unsafe.RArray::cat, RArray::push, RArray::unshift, and RArray::store now
return Result<(), Error>.eval! macro uses anonymous (rather than caller's) binding.Qfalse::new, Qnil::new, Qtrue::new, Qundef::new (use
QFALSE/QNIL/QTRUE/QUNDEF).Error with a specific Ruby type. E.g.
Error::type_error("...") is now Error::new(exception::type_error(), "...")Binding::new. This will be removed in the future as the underlying
rb_binding_new will not function as of Ruby 3.2.isize/i64/usize/u64 on Windows.RArray methods now correctly protect from exceptions (instead
returning Result<_, Error> when an exception occurs).Support for most core classes, String, Symbol, Integer, Float, Array, Hash and more.
String, Symbol, Integer, Float,
Array, Hash and more.Enumerator as a iterator.yield to Ruby blocks.#[init] macro to mark init function to load extension with require.Your coding agent can read these notes before it upgrades. Set up the MCP server →