7 个版本

0.5.0 2023年12月31日
0.4.0 2022年8月20日
0.3.2 2022年8月14日
0.2.1 2022年8月10日
0.1.1-alpha.9 2022年8月10日

#54 in FFI


minutus-mrbgem-template 中使用

MIT 许可证

1.5MB
1K SLoC

Rust 895 SLoC // 0.0% comments Ruby 244 SLoC // 0.0% comments

Minutus

minutus docs.rs ci status license

Minutus 是 mruby 的 Rust 绑定,它允许您无需编写繁琐的模板即可处理 mruby。深受 Magnus 的启发。

通过 minutus,您可以轻松地将 mruby 嵌入 Rust,并通过 Rust 创建 mrbgem

Minutus 还提供了合理的 类型转换,您可以在 mruby 值上定义类型函数,并将 Rust 结构体封装在 mruby 对象中

将 mruby 嵌入 Rust

您可以将 mruby 代码嵌入 Rust 代码中。

使用 link_mruby 功能将 minutus 添加到您的 crate 的依赖项中。

cargo add minutus --features link_mruby

编写代码如下

// src/main.rs

// This enables you to call `some_method` in mruby world.
minutus::define_funcall!{
  fn some_method(self, arr: Vec<i64>) -> i64;
}

fn main() {
    let runtime = minutus::Evaluator::build();

    // Define `some_method` in mruby world
    runtime.evaluate(
      "
      def some_method(arr)
        p arr
        arr.reduce(&:+)
      end
      "
    ).unwrap();

    // Capture mruby's main object
    let main = runtime.evaluate("self").unwrap();

    // Call `some_method` on main object.
    // Arguments and return values are automatically type-casted according to `define_funcall!` definition.
    let retval: i64 = main.some_method(vec![1,2,3,4]).unwrap();
    println!("retval is {}", retval);
}

然后,您可以运行您的代码

$ cargo run
[1, 2, 3, 4] // in mruby workd
retval is 10 // in rust world

如果您想使用自定义 build_config.rb(例如,用于使用 mrbgems),您必须编写自定义 build.rs

Minutus 提供了相应的辅助工具。请参阅 示例/custom-mruby

通过 Rust 创建 mrbgem

安装 minutus-mrbgem-template 并初始化 mrbgem。

$ cargo install minutus-mrbgem-template
$ minutus-mrbgem-template mruby-example
$ tree mruby-example
mruby-example
├── Cargo.lock
├── Cargo.toml
├── LICENSE
├── README.md
├── Rakefile
├── mrbgem.rake
├── mrblib
│   └── mrb_example.rb
├── mruby-example.gem
├── src
│   ├── dummy.c
│   └── lib.rs
└── test
    └── mrb_example.rb

现在,您可以构建和测试 mrbgem。

$ cd mruby-example && rake test
...
  Total: 1456
     OK: 1449
     KO: 0
  Crash: 0
Warning: 0
   Skip: 7
   Time: 0.06 seconds

将 Rust 结构体封装在 mruby 对象中

您可以将 Rust 的结构体封装在 mruby 对象中。

以下示例在 mruby 中定义了 TestMrbgem 类,它具有类方法 new 和实例方法 distancename_with_prefix

#[minutus::wrap(class_method = "new", method = "distance", method = "name_with_prefix")]
struct TestMrbgem {
    x: i64,
    y: i64,
    name: String,
}

impl TestMrbgem {
    #[minutus::class_method]
    pub fn new(x: i64, y: i64, name: String) -> Self {
        Self { x, y, name }
    }

    #[minutus::method]
    pub fn distance(&self, other: &TestMrbgem) -> f64 {
        (((self.x - other.x).pow(2) + (self.y - other.y).pow(2)) as f64).sqrt()
    }

    #[minutus::method]
    pub fn name_with_prefix(&self, prefix: String) -> String {
        [prefix, self.name.clone()].join("_")
    }
}

在 mruby 值上定义类型函数

使用 define_funcall! 宏。

minutus::define_funcall! {
    fn inspect(self) -> String;
    fn concat(self, other: Vec<&str>) -> Vec<String> => "+";
}

fn main() {
    let runtime = minutus::Evaluator::build();

    let mruby_array = runtime.evaluate("['aaa', 'bbb']").unwrap();
    assert_eq!("[\"aaa\", \"bbb\"]", mruby_array.inspect().unwrap());
    assert_eq!(vec![String::from("aaa"), String::from("bbb"), String::from("ccc")], mruby_array.concat(vec!["ccc"]).unwrap());
}

类型转换

有关详细信息,请参阅 minutus/src/types

Rust 类型 mruby 类型
i8i16i32i64isize 整数
u8u16u32u64usize 整数
f32f64 浮点数
字符串 字符串
可选<T> Tnil
(T, U)(T, U, V) [T, U][T, U, V]
Vec<T> 数组
std::collections::HashMap<T, U> Hash
minutus::types::RSymbol Symbol
bool 任意对象
MrbData(由 minutus::wrap 标记的结构体) 对应类

在 mruby 中,任何值都可以转换为 Rust 的 bool。Rust 的 bool 转换为 mruby 的 truefalse

支持的 mruby 版本

3.1.03.2.0 支持。您还可以使用 mruby 的 master 分支,但未进行测试。

[dependencies]
// Use 3.1.0
minutus = { features = ["mruby_3_1_0"] }

// Use master branch
minutus = { features = ["mruby_master"] }

命名

Minutus 是 Magnus 的反义词,意思是 小的

依赖

~6–22MB
~358K SLoC