mlua/tests/userdata.rs

283 lines
8 KiB
Rust
Raw Normal View History

use std::rc::Rc;
2018-02-09 22:52:05 -06:00
2019-10-01 10:11:12 -05:00
use mlua::{
2019-10-14 16:21:30 -05:00
AnyUserData, ExternalError, Function, Lua, MetaMethod, Result, String, UserData,
UserDataMethods, Value,
2019-09-28 09:23:17 -05:00
};
2018-02-09 22:52:05 -06:00
#[test]
2019-09-28 09:23:17 -05:00
fn test_user_data() -> Result<()> {
2018-02-09 22:52:05 -06:00
struct UserData1(i64);
struct UserData2(Box<i64>);
impl UserData for UserData1 {};
impl UserData for UserData2 {};
2019-10-14 16:21:30 -05:00
let lua = Lua::new();
2019-09-28 09:23:17 -05:00
let userdata1 = lua.create_userdata(UserData1(1))?;
let userdata2 = lua.create_userdata(UserData2(Box::new(2)))?;
2018-02-09 22:52:05 -06:00
assert!(userdata1.is::<UserData1>());
assert!(!userdata1.is::<UserData2>());
assert!(userdata2.is::<UserData2>());
assert!(!userdata2.is::<UserData1>());
2018-02-09 22:52:05 -06:00
2019-09-28 09:23:17 -05:00
assert_eq!(userdata1.borrow::<UserData1>()?.0, 1);
assert_eq!(*userdata2.borrow::<UserData2>()?.0, 2);
Ok(())
2018-02-09 22:52:05 -06:00
}
#[test]
2019-09-28 09:23:17 -05:00
fn test_methods() -> Result<()> {
2018-02-09 22:52:05 -06:00
struct MyUserData(i64);
impl UserData for MyUserData {
2020-04-16 08:06:20 -05:00
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
2018-02-09 22:52:05 -06:00
methods.add_method("get_value", |_, data, ()| Ok(data.0));
methods.add_method_mut("set_value", |_, data, args| {
data.0 = args;
Ok(())
});
}
}
2019-10-14 16:21:30 -05:00
let lua = Lua::new();
2018-02-09 22:52:05 -06:00
let globals = lua.globals();
2019-09-28 09:23:17 -05:00
let userdata = lua.create_userdata(MyUserData(42))?;
globals.set("userdata", userdata.clone())?;
lua.load(
2018-02-09 22:52:05 -06:00
r#"
2019-09-28 09:23:17 -05:00
function get_it()
return userdata:get_value()
end
function set_it(i)
return userdata:set_value(i)
end
"#,
2019-09-27 11:38:24 -05:00
)
2019-09-28 09:23:17 -05:00
.exec()?;
let get = globals.get::<_, Function>("get_it")?;
let set = globals.get::<_, Function>("set_it")?;
assert_eq!(get.call::<_, i64>(())?, 42);
userdata.borrow_mut::<MyUserData>()?.0 = 64;
assert_eq!(get.call::<_, i64>(())?, 64);
set.call::<_, ()>(100)?;
assert_eq!(get.call::<_, i64>(())?, 100);
Ok(())
2018-02-09 22:52:05 -06:00
}
#[test]
2019-09-28 09:23:17 -05:00
fn test_metamethods() -> Result<()> {
2018-02-09 22:52:05 -06:00
#[derive(Copy, Clone)]
struct MyUserData(i64);
impl UserData for MyUserData {
2020-04-16 08:06:20 -05:00
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
2018-02-09 22:52:05 -06:00
methods.add_method("get", |_, data, ()| Ok(data.0));
methods.add_meta_function(
MetaMethod::Add,
|_, (lhs, rhs): (MyUserData, MyUserData)| Ok(MyUserData(lhs.0 + rhs.0)),
);
methods.add_meta_function(
MetaMethod::Sub,
|_, (lhs, rhs): (MyUserData, MyUserData)| Ok(MyUserData(lhs.0 - rhs.0)),
);
methods.add_meta_function(MetaMethod::Eq, |_, (lhs, rhs): (MyUserData, MyUserData)| {
Ok(lhs.0 == rhs.0)
});
2018-02-09 22:52:05 -06:00
methods.add_meta_method(MetaMethod::Index, |_, data, index: String| {
if index.to_str()? == "inner" {
Ok(data.0)
} else {
2019-09-28 09:23:17 -05:00
Err("no such custom index".to_lua_err())
2018-02-09 22:52:05 -06:00
}
});
#[cfg(any(feature = "lua53", feature = "lua52"))]
methods.add_meta_method(MetaMethod::Pairs, |lua, data, ()| {
use std::iter::FromIterator;
let stateless_iter = lua.create_function(|_, (data, i): (MyUserData, i64)| {
let i = i + 1;
if i <= data.0 {
return Ok(mlua::Variadic::from_iter(vec![i, i]));
}
return Ok(mlua::Variadic::new());
})?;
Ok((stateless_iter, data.clone(), 0))
});
2018-02-09 22:52:05 -06:00
}
}
2019-10-14 16:21:30 -05:00
let lua = Lua::new();
2018-02-09 22:52:05 -06:00
let globals = lua.globals();
2019-09-28 09:23:17 -05:00
globals.set("userdata1", MyUserData(7))?;
globals.set("userdata2", MyUserData(3))?;
globals.set("userdata3", MyUserData(3))?;
2018-02-09 22:52:05 -06:00
assert_eq!(
2019-09-28 09:23:17 -05:00
lua.load("userdata1 + userdata2").eval::<MyUserData>()?.0,
2018-02-09 22:52:05 -06:00
10
);
#[cfg(any(feature = "lua53", feature = "lua52"))]
let pairs_it = {
lua.load(
r#"
function pairs_it()
local r = 0
for i, v in pairs(userdata1) do
r = r + v
end
return r
end
"#,
)
.exec()?;
globals.get::<_, Function>("pairs_it")?
};
2019-09-28 09:23:17 -05:00
assert_eq!(lua.load("userdata1 - userdata2").eval::<MyUserData>()?.0, 4);
assert_eq!(lua.load("userdata1:get()").eval::<i64>()?, 7);
assert_eq!(lua.load("userdata2.inner").eval::<i64>()?, 3);
#[cfg(any(feature = "lua53", feature = "lua52"))]
assert_eq!(pairs_it.call::<_, i64>(())?, 28);
2019-09-28 09:23:17 -05:00
assert!(lua.load("userdata2.nonexist_field").eval::<()>().is_err());
let userdata2: Value = globals.get("userdata2")?;
let userdata3: Value = globals.get("userdata3")?;
assert!(lua.load("userdata2 == userdata3").eval::<bool>()?);
assert!(userdata2 != userdata3); // because references are differ
assert!(userdata2.equals(userdata3)?);
2019-09-28 09:23:17 -05:00
Ok(())
2018-02-09 22:52:05 -06:00
}
#[test]
2019-09-28 09:23:17 -05:00
fn test_gc_userdata() -> Result<()> {
2018-02-09 22:52:05 -06:00
struct MyUserdata {
id: u8,
}
impl UserData for MyUserdata {
2020-04-16 08:06:20 -05:00
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
2018-02-09 22:52:05 -06:00
methods.add_method("access", |_, this, ()| {
assert!(this.id == 123);
Ok(())
});
}
}
2019-10-14 16:21:30 -05:00
let lua = Lua::new();
2019-09-28 09:23:17 -05:00
lua.globals().set("userdata", MyUserdata { id: 123 })?;
2018-02-09 22:52:05 -06:00
2019-09-27 11:38:24 -05:00
assert!(lua
2019-09-28 09:23:17 -05:00
.load(
2018-08-05 08:51:39 -05:00
r#"
local tbl = setmetatable({
userdata = userdata
}, { __gc = function(self)
-- resurrect userdata
hatch = self.userdata
end })
tbl = nil
userdata = nil -- make table and userdata collectable
collectgarbage("collect")
hatch:access()
"#
2019-09-27 11:38:24 -05:00
)
2019-09-28 09:23:17 -05:00
.exec()
2019-09-27 11:38:24 -05:00
.is_err());
2019-09-28 09:23:17 -05:00
Ok(())
2018-02-09 22:52:05 -06:00
}
#[test]
2019-09-28 09:23:17 -05:00
fn detroys_userdata() -> Result<()> {
struct MyUserdata(Rc<()>);
2018-02-09 22:52:05 -06:00
impl UserData for MyUserdata {}
let rc = Rc::new(());
2018-02-09 22:52:05 -06:00
2019-10-14 16:21:30 -05:00
let lua = Lua::new();
2019-09-28 09:23:17 -05:00
lua.globals().set("userdata", MyUserdata(rc.clone()))?;
2018-02-09 22:52:05 -06:00
assert_eq!(Rc::strong_count(&rc), 2);
2019-09-28 09:23:17 -05:00
// should destroy all objects
let _ = lua.globals().raw_remove("userdata")?;
lua.gc_collect()?;
assert_eq!(Rc::strong_count(&rc), 1);
2019-09-28 09:23:17 -05:00
Ok(())
2018-02-09 22:52:05 -06:00
}
#[test]
2019-09-28 09:23:17 -05:00
fn user_value() -> Result<()> {
2018-02-09 22:52:05 -06:00
struct MyUserData;
2018-02-09 22:52:05 -06:00
impl UserData for MyUserData {}
2019-10-14 16:21:30 -05:00
let lua = Lua::new();
2019-09-28 09:23:17 -05:00
let ud = lua.create_userdata(MyUserData)?;
ud.set_user_value("hello")?;
assert_eq!(ud.get_user_value::<String>()?, "hello");
assert!(ud.get_user_value::<u32>().is_err());
2019-09-28 09:23:17 -05:00
Ok(())
}
#[test]
fn test_functions() -> Result<()> {
struct MyUserData(i64);
impl UserData for MyUserData {
2020-04-16 08:06:20 -05:00
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
2019-09-28 09:23:17 -05:00
methods.add_function("get_value", |_, ud: AnyUserData| {
Ok(ud.borrow::<MyUserData>()?.0)
});
methods.add_function("set_value", |_, (ud, value): (AnyUserData, i64)| {
ud.borrow_mut::<MyUserData>()?.0 = value;
Ok(())
});
methods.add_function("get_constant", |_, ()| Ok(7));
}
}
2019-10-14 16:21:30 -05:00
let lua = Lua::new();
2019-09-28 09:23:17 -05:00
let globals = lua.globals();
let userdata = lua.create_userdata(MyUserData(42))?;
globals.set("userdata", userdata.clone())?;
lua.load(
r#"
function get_it()
return userdata:get_value()
end
function set_it(i)
return userdata:set_value(i)
end
function get_constant()
return userdata.get_constant()
end
"#,
)
.exec()?;
let get = globals.get::<_, Function>("get_it")?;
let set = globals.get::<_, Function>("set_it")?;
let get_constant = globals.get::<_, Function>("get_constant")?;
assert_eq!(get.call::<_, i64>(())?, 42);
userdata.borrow_mut::<MyUserData>()?.0 = 64;
assert_eq!(get.call::<_, i64>(())?, 64);
set.call::<_, ()>(100)?;
assert_eq!(get.call::<_, i64>(())?, 100);
assert_eq!(get_constant.call::<_, i64>(())?, 7);
Ok(())
2018-02-09 22:52:05 -06:00
}