2 个不稳定版本
0.2.0 | 2020 年 7 月 1 日 |
---|---|
0.1.0 | 2020 年 6 月 28 日 |
#2603 在 Rust 模式
21KB
rudeboy
rudeboy - Rlua 用户数据扩展库
提供 derive 宏和 impl 块属性宏,允许通过 rlua
包将 Rust 方法暴露给 Lua,同时生成索引元方法。
用法
该库允许以下五种主要用法,以下各节将进行说明。
仅索引元方法
这允许通过 instance.field
语法从 Lua 访问 UserData 结构体的实例字段,但不生成或允许用户添加任何其他方法。
use rudeboy::IndexSealed;
#[derive(IndexSealed)]
struct Foo {
bar: String,
baz: f64,
}
let lua = rlua::Lua::new();
lua.context(|ctx| {
// Add an instance of Foo to the lua environment
let globals = ctx.globals();
let bar = "bar".to_string();
let baz = 23.0;
globals.set("a_foo", Foo { bar: bar.clone(), baz })?;
// Use the index metamethod to access fields
let lua_bar = ctx.load("a_foo.bar").eval::<String>()?;
assert_eq!(lua_bar, bar);
let lua_baz = ctx.load("a_foo.baz").eval::<f64>()?;
assert_eq!(lua_baz, baz);
Ok(())
})?;
索引元方法和额外的用户定义
这允许通过 instance.field
语法从 Lua 访问 UserData 结构体的实例字段,但不生成 rlua::UserData
的 impl。用户必须使用 RudeboyIndex
特质来添加索引元方法,但也可以自由添加从 Lua 访问的其他方法。
use rudeboy::Index;
#[derive(Index)]
struct Foo {
bar: String,
baz: f64,
}
impl rlua::UserData for Foo {
fn add_methods<'lua, M: ::rlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
// Use the rudeboy-generated trait to add the index metamethod
use rudeboy::RudeboyIndex;
Foo::generate_index(methods);
// Add additional user-defined methods
methods.add_method("user_method", |_, data, ()| {
Ok(data.baz * 2.0)
});
}
}
let lua = rlua::Lua::new();
lua.context(|ctx| {
// Add an instance of Foo to the lua environment
let globals = ctx.globals();
let bar = "bar".to_string();
let baz = 23.0;
globals.set("a_foo", Foo { bar: bar.clone(), baz })?;
// Use the index metamethod to access fields
let lua_bar = ctx.load("a_foo.bar").eval::<String>()?;
assert_eq!(lua_bar, bar);
let lua_baz = ctx.load("a_foo.baz").eval::<f64>()?;
assert_eq!(lua_baz, baz);
// Use the user defined method
let udm = ctx.load("a_foo:user_method()").eval::<f64>()?;
assert_eq!(baz * 2.0, udm);
Ok(())
})?;
仅索引元方法和 Rust 方法
这生成索引元方法,并将标记 impl 块中的方法暴露给 Lua,同时生成 UserData 的 impl。然而,用户不能添加任何进一步的用户定义方法。
use rudeboy::{Index, MethodsSealed};
#[derive(Index)]
struct Foo {
bar: String,
baz: f64,
}
#[MethodsSealed]
impl Foo {
// Methods must take self as their receiver...
fn double(&self) -> f64 {
self.baz * 2.0
}
// ... but can take mut self as well
fn set_baz(&mut self, baz: f64) {
self.baz = baz;
}
}
let lua = rlua::Lua::new();
lua.context(|ctx| {
// Add an instance of Foo to the lua environment
let globals = ctx.globals();
let bar = "bar".to_string();
let baz = 23.0;
globals.set("a_foo", Foo { bar: bar.clone(), baz })?;
// Use the index metamethod to access fields
let lua_bar = ctx.load("a_foo.bar").eval::<String>()?;
assert_eq!(lua_bar, bar);
let lua_baz = ctx.load("a_foo.baz").eval::<f64>()?;
assert_eq!(lua_baz, baz);
// Use the immutable method
let doubled = ctx.load("a_foo:double()").eval::<f64>()?;
assert_eq!(baz * 2.0, doubled);
// Use the mutable method
ctx.load("a_foo:set_baz(5.0)").exec()?;
let new_baz = ctx.load("a_foo.baz").eval::<f64>()?;
assert_eq!(new_baz, 5.0);
Ok(())
})?;
索引元方法和 Rust 方法以及额外的用户定义
这生成索引元方法,并将标记 impl 块中的方法暴露给 Lua,但不生成 UserData 的 impl。然后,用户可以使用 rlua::UserData
添加额外的方法,但必须使用 RudeboyIndex
和 RudeboyMethods
特质将生成的方法添加到用户数据中。
use rudeboy::{Index, Methods};
#[derive(Index)]
struct Foo {
bar: String,
baz: f64,
}
#[Methods]
impl Foo {
// Methods must take self as their receiver...
fn double(&self) -> f64 {
self.baz * 2.0
}
// ... but can take mut self as well
fn set_baz(&mut self, baz: f64) {
self.baz = baz;
}
}
impl rlua::UserData for Foo {
fn add_methods<'lua, M: ::rlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
// Use the rudeboy-generated trait to add the index metamethod
use rudeboy::RudeboyIndex;
Foo::generate_index(methods);
// Use the rudeboy-generated trait to add the methods from the tagged
// impl block
use rudeboy::RudeboyMethods;
Foo::generate_methods(methods);
// Add additional user-defined methods
methods.add_method("user_method", |_, data, ()| {
Ok(data.baz * 2.0)
});
}
}
let lua = rlua::Lua::new();
lua.context(|ctx| {
// Add an instance of Foo to the lua environment
let globals = ctx.globals();
let bar = "bar".to_string();
let baz = 23.0;
globals.set("a_foo", Foo { bar: bar.clone(), baz })?;
// Use the index metamethod to access fields
let lua_bar = ctx.load("a_foo.bar").eval::<String>()?;
assert_eq!(lua_bar, bar);
let lua_baz = ctx.load("a_foo.baz").eval::<f64>()?;
assert_eq!(lua_baz, baz);
// Use the immutable method
let udm = ctx.load("a_foo:double()").eval::<f64>()?;
assert_eq!(baz * 2.0, udm);
// Use the mutable method
ctx.load("a_foo:set_baz(5.0)").exec()?;
let new_baz = ctx.load("a_foo.baz").eval::<f64>()?;
assert_eq!(new_baz, 5.0);
// Use the user defined method
let udm = ctx.load("a_foo:user_method()").eval::<f64>()?;
assert_eq!(new_baz * 2.0, udm);
Ok(())
})?;
无索引元方法的 Rust 方法
在 impl 块中暴露方法到 Lua,而不为类型创建索引元方法。同时生成 rlua::UserData
的 impl,这意味着用户不能添加额外的用户定义方法。
本例使用MethodsSealed
将impl块中的方法添加进来,并为该类型生成一个rlua::UserData
的impl实现。请注意,MethodsSealed
期望类型有一个RudeboyIndex
的实现,因此我们必须使用NoIndex
宏来提供一个空的实现。
use rudeboy::{NoIndex, MethodsSealed};
// Derives Clone so that an instance can be retrieved from the lua context
#[derive(Clone, NoIndex)]
struct Foo {
bar: String,
baz: f64,
}
#[MethodsSealed]
impl Foo {
// Methods must take self as their receiver...
fn double(&self) -> f64 {
self.baz * 2.0
}
// ... but can take mut self as well
fn set_baz(&mut self, baz: f64) {
self.baz = baz;
}
}
let lua = rlua::Lua::new();
lua.context(|ctx| {
// Add an instance of Foo to the lua environment
let globals = ctx.globals();
let bar = "bar".to_string();
let baz = 23.0;
globals.set("a_foo", Foo { bar: bar.clone(), baz })?;
// Use the immutable method
let udm = ctx.load("a_foo:double()").eval::<f64>()?;
assert_eq!(baz * 2.0, udm);
// Use the mutable method
ctx.load("a_foo:set_baz(5.0)").exec()?;
let new_foo = ctx.load("a_foo").eval::<Foo>()?;
assert_eq!(new_foo.baz, 5.0);
Ok(())
})?;
没有索引元方法的Rust方法,但有用户定义的方法
这会生成一个RudeboyMethods
的实现,该实现将添加来自impl块的方法,但不会生成索引元方法或为rlua::UserData
生成impl。这允许用户添加额外的用户定义方法。
请注意,因为这种方法没有使用MethodsSealed
,所以不需要使用NoIndex
宏。
use rudeboy::{Index, Methods};
// Derives Clone so that an instance can be retrieved from the lua context
#[derive(Clone)]
struct Foo {
bar: String,
baz: f64,
}
#[Methods]
impl Foo {
// Methods must take self as their receiver...
fn double(&self) -> f64 {
self.baz * 2.0
}
// ... but can take mut self as well
fn set_baz(&mut self, baz: f64) {
self.baz = baz;
}
}
impl rlua::UserData for Foo {
fn add_methods<'lua, M: ::rlua::UserDataMethods<'lua, Self>>(methods: &mut M) {
// Note: the call for RudeboyIndex::generate_index is simply ommitted
// Use the rudeboy-generated trait to add the methods from the tagged
// impl block
use rudeboy::RudeboyMethods;
Foo::generate_methods(methods);
// Add additional user-defined methods
methods.add_method("user_method", |_, data, ()| {
Ok(data.baz * 2.0)
});
}
}
let lua = rlua::Lua::new();
lua.context(|ctx| {
// Add an instance of Foo to the lua environment
let globals = ctx.globals();
let bar = "bar".to_string();
let baz = 23.0;
globals.set("a_foo", Foo { bar: bar.clone(), baz })?;
// Use the immutable method
let udm = ctx.load("a_foo:double()").eval::<f64>()?;
assert_eq!(baz * 2.0, udm);
// Use the mutable method
ctx.load("a_foo:set_baz(5.0)").exec()?;
let new_foo = ctx.load("a_foo").eval::<Foo>()?;
assert_eq!(new_foo.baz, 5.0);
// Use the user defined method
let udm = ctx.load("a_foo:user_method()").eval::<f64>()?;
assert_eq!(new_foo.baz * 2.0, udm);
Ok(())
})?;
许可证:MIT
依赖关系
~2.5MB
~51K SLoC