{"id":13671594,"url":"https://github.com/matsadler/magnus","last_synced_at":"2025-05-13T17:12:47.336Z","repository":{"id":37705156,"uuid":"367789868","full_name":"matsadler/magnus","owner":"matsadler","description":"Ruby bindings for Rust. Write Ruby extension gems in Rust, or call Ruby from Rust.","archived":false,"fork":false,"pushed_at":"2025-05-08T03:47:13.000Z","size":1880,"stargazers_count":719,"open_issues_count":24,"forks_count":38,"subscribers_count":12,"default_branch":"main","last_synced_at":"2025-05-08T04:19:48.224Z","etag":null,"topics":["ffi","ruby","rust"],"latest_commit_sha":null,"homepage":"https://docs.rs/magnus/latest/magnus/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/matsadler.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-05-16T05:09:11.000Z","updated_at":"2025-05-08T03:47:18.000Z","dependencies_parsed_at":"2023-12-03T20:19:58.510Z","dependency_job_id":"09a6e3d0-d803-43bc-8a8f-9c33c09b3eae","html_url":"https://github.com/matsadler/magnus","commit_stats":{"total_commits":722,"total_committers":23,"mean_commits":"31.391304347826086","dds":"0.12049861495844871","last_synced_commit":"faad1424ae34a477f47d5b5f40b8345776c88026"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matsadler%2Fmagnus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matsadler%2Fmagnus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matsadler%2Fmagnus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matsadler%2Fmagnus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/matsadler","download_url":"https://codeload.github.com/matsadler/magnus/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253990482,"owners_count":21995775,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ffi","ruby","rust"],"created_at":"2024-08-02T09:01:14.083Z","updated_at":"2025-05-13T17:12:42.305Z","avatar_url":"https://github.com/matsadler.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"# Magnus\n\nHigh level Ruby bindings for Rust. Write Ruby extension gems in Rust, or call\nRuby code from a Rust binary.\n\n[API Docs] | [GitHub] | [crates.io]\n\n[API Docs]: https://docs.rs/magnus/latest/magnus/\n[GitHub]: https://github.com/matsadler/magnus\n[crates.io]: https://crates.io/crates/magnus\n\n[Getting Started] | [Type Conversions] | [Safety] | [Compatibility]\n\n[Getting Started]: #getting-started\n[Type Conversions]: #type-conversions\n[Safety]: #safety\n[Compatibility]: #compatibility\n\n## Examples\n\n### Defining Methods\n\nUsing Magnus, regular Rust functions can be bound to Ruby as methods with\nautomatic type conversion. Callers passing the wrong arguments or incompatible\ntypes will get the same kind of `ArgumentError` or `TypeError` they are used to\nseeing from Ruby's built in methods.\n\nDefining a function (with no Ruby `self` argument):\n\n```rust\nfn fib(n: usize) -\u003e usize {\n    match n {\n        0 =\u003e 0,\n        1 | 2 =\u003e 1,\n        _ =\u003e fib(n - 1) + fib(n - 2),\n    }\n}\n\n#[magnus::init]\nfn init(ruby: \u0026magnus::Ruby) -\u003e Result\u003c(), Error\u003e {\n    ruby.define_global_function(\"fib\", magnus::function!(fib, 1));\n    Ok(())\n}\n```\n\nDefining a method (with a Ruby `self` argument):\n\n```rust\nfn is_blank(rb_self: String) -\u003e bool {\n    !rb_self.contains(|c: char| !c.is_whitespace())\n}\n\n#[magnus::init]\nfn init(ruby: \u0026magnus::Ruby) -\u003e Result\u003c(), Error\u003e {\n    // returns the existing class if already defined\n    let class = ruby.define_class(\"String\", ruby.class_object())?;\n    // 0 as self doesn't count against the number of arguments\n    class.define_method(\"blank?\", magnus::method!(is_blank, 0))?;\n    Ok(())\n}\n```\n\n### Calling Ruby Methods\n\nSome Ruby methods have direct counterparts in Ruby's C API and therefore in\nMagnus. Ruby's `Object#frozen?` method is available as\n`magnus::ReprValue::check_frozen`, or `Array#[]` becomes `magnus::RArray::aref`.\n\nOther Ruby methods that are defined only in Ruby must be called with\n`magnus::ReprValue::funcall`. All of Magnus' Ruby wrapper types implement the\n`ReprValue` trait, so `funcall` can be used on all of them.\n\n```rust\nlet s: String = value.funcall(\"test\", ())?; // 0 arguments\nlet x: bool = value.funcall(\"example\", (\"foo\",))?; // 1 argument\nlet i: i64 = value.funcall(\"other\", (42, false))?; // 2 arguments, etc\n```\n\n`funcall` will convert return types, returning `Err(magnus::Error)` if the type\nconversion fails or the method call raised an error. To skip type conversion\nmake sure the return type is `magnus::Value`.\n\n### Wrapping Rust Types in Ruby Objects\n\nMagnus allows you to wrap Rust structs and enums as Ruby objects, enabling seamless interaction between Rust and Ruby. This functionality is ideal for exposing Rust logic to Ruby modules.\n\nUse one of the following approaches to expose a Rust type to Ruby:\n\n* A convenience macro [`#[magnus::wrap]`][magnus-wrap].\n* More customised approach by implementing the [`magnus::TypedData`] trait.\n\n[magnus-wrap]: https://docs.rs/magnus/latest/magnus/attr.wrap.html\n[`magnus::TypedData`]: https://docs.rs/magnus/latest/magnus/derive.TypedData.html\n\nThen this Rust type can be:\n\n* Returned to Ruby as a wrapped object.\n* Passed back to Rust and automatically unwrapped to a native Rust reference.\n\n#### Basic Usage\n\nHere’s how you can wrap a simple Rust struct and expose its methods to Ruby:\n\n```rust\nuse magnus::{function, method, prelude::*, Error, Ruby};\n\n#[magnus::wrap(class = \"Point\")]\nstruct Point {\n    x: isize,\n    y: isize,\n}\n\nimpl Point {\n    fn new(x: isize, y: isize) -\u003e Self {\n        Self { x, y }\n    }\n\n    fn x(\u0026self) -\u003e isize {\n        self.x\n    }\n\n    fn y(\u0026self) -\u003e isize {\n        self.y\n    }\n\n    fn distance(\u0026self, other: \u0026Point) -\u003e f64 {\n        (((other.x - self.x).pow(2) + (other.y - self.y).pow(2)) as f64).sqrt()\n    }\n}\n\n#[magnus::init]\nfn init(ruby: \u0026Ruby) -\u003e Result\u003c(), Error\u003e {\n    let class = ruby.define_class(\"Point\", ruby.class_object())?;\n    class.define_singleton_method(\"new\", function!(Point::new, 2))?;\n    class.define_method(\"x\", method!(Point::x, 0))?;\n    class.define_method(\"y\", method!(Point::y, 0))?;\n    class.define_method(\"distance\", method!(Point::distance, 1))?;\n    Ok(())\n}\n```\n\n#### Handling Mutability\n\nBecause Ruby's GC manages the memory where your Rust type is stored, Magnus can't bind functions with mutable references. To allow mutable fields in wrapped Rust structs, you can use the newtype pattern with `RefCell`:\n\n```rust\nuse std::cell::RefCell;\n\nstruct Point {\n    x: isize,\n    y: isize,\n}\n\n#[magnus::wrap(class = \"Point\")]\nstruct MutPoint(RefCell\u003cPoint\u003e);\n\nimpl MutPoint {\n    fn set_x(\u0026self, i: isize) {\n        self.0.borrow_mut().x = i;\n    }\n}\n```\n\nSee [`examples/mut_point.rs`] for the complete example.\n\n[`examples/mut_point.rs`]: https://github.com/matsadler/magnus/blob/main/examples/mut_point.rs\n\n#### Supporting Subclassing\n\nTo enable Ruby subclassing for wrapped Rust types, the type must:\n\n* Implement the `Default` trait.\n* Define an allocator.\n* Define an initialiser.\n\n``` rust\n#[derive(Default)]\nstruct Point {\n    x: isize,\n    y: isize,\n}\n\n#[derive(Default)]\n#[wrap(class = \"Point\")]\nstruct MutPoint(RefCell\u003cPoint\u003e);\n\nimpl MutPoint {\n    fn initialize(\u0026self, x: isize, y: isize) {\n        let mut this = self.0.borrow_mut();\n        this.x = x;\n        this.y = y;\n    }\n}\n\n#[magnus::init]\nfn init(ruby: \u0026Ruby) -\u003e Result\u003c(), Error\u003e {\n    let class = ruby.define_class(\"Point\", ruby.class_object()).unwrap();\n    class.define_alloc_func::\u003cMutPoint\u003e();\n    class.define_method(\"initialize\", method!(MutPoint::initialize, 2))?;\n    Ok(())\n}\n```\n\n#### Error Handling\n\nUse `magnus::Error` to propagate errors to Ruby from Rust:\n\n```rust\n#[magnus::wrap(class = \"Point\")]\nstruct MutPoint(RefCell\u003cPoint\u003e);\n\nimpl MutPoint {\n    fn add_x(ruby: \u0026Ruby, rb_self: \u0026Self, val: isize) -\u003e Result\u003cisize, Error\u003e {\n        if let Some(sum) = rb_self.0.borrow().x.checked_add(val) {\n            rb_self.0.borrow_mut().x = sum;\n            Ok(sum)\n        } else {\n            return Err(Error::new(ruby.exception_range_error(), \"result out of range\"));\n        }\n    }\n}\n```\n\n## Getting Started\n\n### Writing an extension gem (calling Rust from Ruby)\n\nRuby extensions must be built as dynamic system libraries, this can be done by\nsetting the `crate-type` attribute in your `Cargo.toml`.\n\n**`Cargo.toml`**\n\n```toml\n[lib]\ncrate-type = [\"cdylib\"]\n\n[dependencies]\nmagnus = \"0.7\"\n```\n\nWhen Ruby loads your extension it calls an 'init' function defined in your\nextension. In this function you will need to define your Ruby classes and bind\nRust functions to Ruby methods. Use the `#[magnus::init]` attribute to mark\nyour init function so it can be correctly exposed to Ruby.\n\n**`src/lib.rs`**\n\n```rust\nuse magnus::{function, Error, Ruby};\n\nfn distance(a: (f64, f64), b: (f64, f64)) -\u003e f64 {\n    ((b.0 - a.0).powi(2) + (b.1 - a.1).powi(2)).sqrt()\n}\n\n#[magnus::init]\nfn init(ruby: \u0026Ruby) -\u003e Result\u003c(), Error\u003e {\n    ruby.define_global_function(\"distance\", function!(distance, 2));\n}\n```\n\nIf you wish to package your extension as a Gem, we recommend using the\n[`rb_sys` gem] to build along with `rake-compiler`. These tools will\nautomatically build your Rust extension as a dynamic library, and then package\nit as a gem.\n\n*Note*: The newest version of rubygems does have beta support for compiling\nRust, so in the future the `rb_sys` gem won't be necessary.\n\n**`my_example_gem.gemspec`**\n```ruby\nspec.extensions = [\"ext/my_example_gem/extconf.rb\"]\n\n# needed until rubygems supports Rust support is out of beta\nspec.add_dependency \"rb_sys\", \"~\u003e 0.9.39\"\n\n# only needed when developing or packaging your gem\nspec.add_development_dependency \"rake-compiler\", \"~\u003e 1.2.0\"\n```\n\nThen, we add an `extconf.rb` file to the `ext` directory. Ruby will execute\nthis file during the compilation process, and it will generate a `Makefile` in\nthe `ext` directory. See the [`rb_sys` gem] for more information.\n\n**`ext/my_example_gem/extconf.rb`**\n\n```ruby\nrequire \"mkmf\"\nrequire \"rb_sys/mkmf\"\n\ncreate_rust_makefile(\"my_example_gem/my_example_gem\")\n```\n\nSee the [`rust_blank`] example for examples of `extconf.rb` and `Rakefile`.\nRunning `rake compile` will place the extension at\n`lib/my_example_gem/my_example_gem.so` (or `.bundle` on macOS), which you'd\nload from Ruby like so:\n\n**`lib/my_example_gem.rb`**\n\n```ruby\nrequire_relative \"my_example_gem/my_example_gem\"\n```\n\nFor a more detailed example (including cross-compilation and more), see the\n[`rb-sys` example project]. Although the code in `lib.rs` does not feature\nmagnus, but it will compile and run properly.\n\n[`rb_sys` gem]: https://github.com/oxidize-rb/rb-sys/tree/main/gem\n[`rake-compiler`]: https://github.com/rake-compiler/rake-compiler\n[`rust_blank`]: https://github.com/matsadler/magnus/tree/main/examples/rust_blank/ext/rust_blank\n[`rb-sys` example project]: https://github.com/oxidize-rb/rb-sys/tree/main/examples/rust_reverse\n\n### Embedding Ruby in Rust\n\nTo call Ruby from a Rust program, enable the `embed` feature:\n\n**`Cargo.toml`**\n\n```toml\n[dependencies]\nmagnus = { version = \"0.7\", features = [\"embed\"] }\n```\n\nThis enables linking to Ruby and gives access to the `embed` module.\n`magnus::embed::init` must be called before calling Ruby and the value it\nreturns must not be dropped until you are done with Ruby. `init` can not be\ncalled more than once.\n\n**`src/main.rs`**\n\n```rust\nuse magnus::eval;\n\nfn main() {\n    magnus::Ruby::init(|ruby| {\n        let val: f64 = eval!(ruby, \"a + rand\", a = 1)?;\n\n        println!(\"{}\", val);\n\n        Ok(())\n    }).unwrap();\n}\n```\n\n## Type Conversions\n\nMagnus will automatically convert between Rust and Ruby types, including\nconverting Ruby exceptions to Rust `Result`s and vice versa.\n\nThese conversions follow the pattern set by Ruby's core and standard libraries,\nwhere many conversions will delegate to a `#to_\u003ctype\u003e` method if the object is\nnot of the requested type, but does implement the `#to_\u003ctype\u003e` method.\n\nBelow are tables outlining many common conversions. See the Magnus api\ndocumentation for the full list of types.\n\n### Rust functions accepting values from Ruby\n\nSee `magnus::TryConvert` for more details.\n\n| Rust function argument                                               | accepted from Ruby                      |\n| -------------------------------------------------------------------- | --------------------------------------- |\n| `i8`,`i16`,`i32`,`i64`,`isize`, `magnus::Integer`                    | `Integer`, `#to_int`                    |\n| `u8`,`u16`,`u32`,`u64`,`usize`                                       | `Integer`, `#to_int`                    |\n| `f32`,`f64`, `magnus::Float`                                         | `Float`, `Numeric`                      |\n| `String`, `PathBuf`, `char`, `magnus::RString`, `bytes::Bytes`‡      | `String`, `#to_str`                     |\n| `magnus::Symbol`                                                     | `Symbol`, `#to_sym`                     |\n| `bool`                                                               | any object                              |\n| `magnus::Range`                                                      | `Range`                                 |\n| `magnus::Encoding`, `magnus::RbEncoding`                             | `Encoding`, encoding name as a string   |\n| `Option\u003cT\u003e`                                                          | `T` or `nil`                            |\n| `(T, U)`, `(T, U, V)`, etc                                           | `[T, U]`, `[T, U, V]`, etc, `#to_ary`   |\n| `[T; N]`                                                             | `[T]`, `#to_ary`                        |\n| `magnus::RArray`                                                     | `Array`, `#to_ary`                      |\n| `magnus::RHash`                                                      | `Hash`, `#to_hash`                      |\n| `std::time::SystemTime`, `magnus::Time`, `chrono::DateTime\u003cT\u003e`§      | `Time`                                  |\n| `magnus::Value`                                                      | any object                              |\n| `Vec\u003cT\u003e`\\*                                                           | `[T]`, `#to_ary`                        |\n| `HashMap\u003cK, V\u003e`\\*                                                    | `{K =\u003e V}`, `#to_hash`                  |\n| `\u0026T`, `typed_data::Obj\u003cT\u003e` where `T: TypedData`†                     | instance of `\u003cT as TypedData\u003e::class()` |\n\n\\* when converting to `Vec` and `HashMap` the types of `T`/`K`,`V` must be native Rust types.\n\n† see the `wrap` macro.\n\n‡ when the `bytes` feature is enabled\n\n§ when the `chrono` feature is enabled; `T` can be `Utc` or `FixedOffset`.\n\n### Rust returning / passing values to Ruby\n\nSee `magnus::IntoValue` for more details, plus `magnus::method::ReturnValue`\nand `magnus::ArgList` for some additional details.\n\n| returned from Rust / calling Ruby from Rust        | received in Ruby                        |\n| -------------------------------------------------- | --------------------------------------- |\n| `i8`,`i16`,`i32`,`i64`,`isize`                     | `Integer`                               |\n| `u8`,`u16`,`u32`,`u64`,`usize`                     | `Integer`                               |\n| `f32`, `f64`                                       | `Float`                                 |\n| `String`, `\u0026str`, `char`, `\u0026Path`, `PathBuf`       | `String`                                |\n| `bool`                                             | `true`/`false`                          |\n| `()`                                               | `nil`                                   |\n| `Range`, `RangeFrom`, `RangeTo`, `RangeInclusive`  | `Range`                                 |\n| `Option\u003cT\u003e`                                        | `T` or `nil`                            |\n| `Result\u003cT, magnus::Error\u003e` (return only)           | `T` or raises error                     |\n| `(T, U)`, `(T, U, V)`, etc, `[T; N]`, `Vec\u003cT\u003e`     | `Array`                                 |\n| `HashMap\u003cK, V\u003e`                                    | `Hash`                                  |\n| `std::time::SystemTime`                            | `Time`                                  |\n| `T`, `typed_data::Obj\u003cT\u003e` where `T: TypedData`\\*  | instance of `\u003cT as TypedData\u003e::class()` |\n\n\\* see the `wrap` macro.\n\n### Conversions via Serde\n\nRust types can also be converted to Ruby, and vice versa, using [Serde] with\nthe [`serde_magnus`] crate.\n\n[Serde]: https://github.com/serde-rs/serde\n[`serde_magnus`]: https://github.com/OneSignal/serde-magnus\n\n### Manual Conversions\n\nThere may be cases where you want to bypass the automatic type conversions, to\ndo this use the type `magnus::Value` and then manually convert or type check\nfrom there.\n\nFor example, if you wanted to ensure your function is always passed a UTF-8\nencoded String so you can take a reference without allocating you could do the\nfollowing:\n\n```rust\nfn example(ruby: \u0026Ruby, val: magnus::Value) -\u003e Result\u003c(), magnus::Error\u003e {\n    // checks value is a String, does not call #to_str\n    let r_string = RString::from_value(val)\n        .ok_or_else(|| magnus::Error::new(ruby.exception_type_error(), \"expected string\"))?;\n    // error on encodings that would otherwise need converting to utf-8\n    if !r_string.is_utf8_compatible_encoding() {\n        return Err(magnus::Error::new(\n            ruby.exception_encoding_error(),\n            \"string must be utf-8\",\n        ));\n    }\n    // RString::as_str is unsafe as it's possible for Ruby to invalidate the\n    // str as we hold a reference to it. The easiest way to ensure the \u0026str\n    // stays valid is to avoid any other calls to Ruby for the life of the\n    // reference (the rest of the unsafe block).\n    unsafe {\n        let s = r_string.as_str()?;\n        // ...\n    }\n    Ok(())\n}\n```\n\n## Safety\n\nWhen using Magnus, in Rust code, Ruby objects must be kept on the stack. If\nobjects are moved to the heap the Ruby GC can not reach them, and they may be\ngarbage collected. This could lead to memory safety issues.\n\nIt is not possible to enforce this rule in Rust's type system or via the borrow\nchecker, users of Magnus must maintain this rule manually.\n\nAn example of something that breaks this rule would be storing a Ruby object in\na Rust heap allocated data structure, such as `Vec`, `HashMap`, or `Box`. This\nmust be avoided at all costs.\n\nWhile it would be possible to mark any functions that could expose this unsafty\nas `unsafe`, that would mean that almost every interaction with Ruby would\nbe `unsafe`. This would leave no way to differentiate the *really* unsafe\nfunctions that need much more care to use.\n\nOther than this, Magnus strives to match Rust's usual safety guaranties for\nusers of the library. Magnus itself contains a large amount of code marked with\nthe `unsafe` keyword, it is impossible to interact with Ruby's C-api without\nthis, but users of Magnus should be able to do most things without needing to\nuse `unsafe`.\n\n## Compatibility\n\nRuby versions 3.0, 3.1, 3.2, and 3.3 are fully supported.\n\nMagnus currently works with, and is still tested against, Ruby 2.7, but as this\nversion of the language is no longer supported by the Ruby developers it is not\nrecommended and future support in Magnus is not guaranteed.\n\nRuby bindings will be generated at compile time, this may require libclang to\nbe installed.\n\nThe Minimum supported Rust version is currently Rust 1.65.\n\nSupport for statically linking Ruby is provided via the lower-level [rb-sys]\ncrate, and can be enabled by adding the following to your `Cargo.toml`:\n\n```toml\n# * should select the same version used by Magnus\nrb-sys = { version = \"*\", default-features = false, features = [\"ruby-static\"] }\n```\n\nCross-compilation is supported by rb-sys [for the platforms listed here][plat].\n\nMagnus is not tested on 32 bit systems. Efforts are made to ensure it compiles.\nPatches are welcome.\n\n[plat]: https://github.com/oxidize-rb/rb-sys#supported-platforms\n\n## Crates that work with Magnus\n\n### rb-sys\n\nMagnus uses [rb-sys] to provide the low-level bindings to Ruby. The\n`rb-sys` feature enables the [`rb_sys`][rb_sys_module] module for\nadvanced interoperability with rb-sys, allows you to access low-level Ruby APIs\nwhich Magnus does not expose.\n\n[rb-sys]: https://github.com/oxidize-rb/rb-sys/tree/main/crates/rb-sys\n[rb_sys_module]: https://docs.rs/magnus/latest/magnus/rb_sys/index.html\n\n### `serde_magnus`\n\n[`serde_magnus`] integrates [Serde] and Magnus for seamless serialisation and\ndeserialisation of Rust to Ruby data structures and vice versa.\n\n## Users\n\n* [`halton`](https://github.com/matsadler/halton-rb) a Ruby gem providing a\n  highly optimised method for generating Halton sequences.\n* [`optify`](https://github.com/juharris/optify) a Ruby gem to\n  simplify using configuration files to manage options for experiments.\n  It has a GitHub action to publish the gem for different architectures to RubyGems\n  with a RBI file for type hints.\n\nPlease open a [pull request](https://github.com/matsadler/magnus/pulls) if\nyou'd like your project listed here.\n\n## Troubleshooting\n\n### Issues with static linking\n\nIf you encounter an error such as `symbol not found in flat namespace\n'_rb_ext_ractor_safe'` when embedding static Ruby, you will need to instruct\nCargo not to strip code that it thinks is dead.\n\nIn you the same directory as your `Cargo.toml` file, create a\n`.cargo/config.toml` file with the following contents:\n\n```toml\n[build]\n# Without this flag, when linking static libruby, the linker removes symbols\n# (such as `_rb_ext_ractor_safe`) which it thinks are dead code... but they are\n# not, and they need to be included for the `embed` feature to work with static\n# Ruby.\nrustflags = [\"-C\", \"link-dead-code=on\"]\n```\n\n## Naming\n\nMagnus is named after *Magnus the Red* a character from the Warhammer 40,000\nuniverse. A sorcerer who believed he could tame the psychic energy of the Warp.\nUltimately, his hubris lead to his fall to Chaos, but let's hope using this\nlibrary turns out better for you.\n\n## License\n\nThis project is licensed under the MIT license, see [LICENSE].\n\n[LICENSE]: https://github.com/matsadler/magnus/blob/main/LICENSE\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatsadler%2Fmagnus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmatsadler%2Fmagnus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatsadler%2Fmagnus/lists"}