Something went wrong. Try again.
Personal fork of prime agent. Mirror of: https://mnemosyne.sigilzero.dev/sigilzero/prime-agent
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573use std::cell::Cell;use std::rc::Rc;use std::string::String as StdString;use std::sync::Arc;
use mlua::{ AnyUserData, Error, Function, Lua, MetaMethod, ObjectLike, Result, String, UserData, UserDataFields, UserDataMethods, UserDataRegistry,};
#[test]fn test_scope_func() -> Result<()> { let lua = Lua::new();
let rc = Rc::new(Cell::new(0)); lua.scope(|scope| { let rc2 = rc.clone(); let f = scope.create_function(move |_, ()| { rc2.set(42); Ok(()) })?; lua.globals().set("f", &f)?; f.call::<()>(())?; assert_eq!(Rc::strong_count(&rc), 2); Ok(()) })?; assert_eq!(rc.get(), 42); assert_eq!(Rc::strong_count(&rc), 1);
match lua.globals().get::<Function>("f")?.call::<()>(()) { Err(Error::CallbackError { ref cause, .. }) => match *cause.as_ref() { Error::CallbackDestructed => {} ref err => panic!("wrong error type {:?}", err), }, r => panic!("improper return for destructed function: {:?}", r), };
Ok(())}
#[test]fn test_scope_capture() -> Result<()> { let lua = Lua::new();
let mut i = 0; lua.scope(|scope| { scope .create_function_mut(|_, ()| { i = 42; Ok(()) })? .call::<()>(()) })?; assert_eq!(i, 42);
Ok(())}
#[test]fn test_scope_outer_lua_access() -> Result<()> { let lua = Lua::new();
let table = lua.create_table()?; lua.scope(|scope| scope.create_function(|_, ()| table.set("a", "b"))?.call::<()>(()))?; assert_eq!(table.get::<String>("a")?, "b");
Ok(())}
#[test]fn test_scope_capture_scope() -> Result<()> { let lua = Lua::new();
let i = Cell::new(0); lua.scope(|scope| { let f = scope.create_function(|_, ()| { scope.create_function(|_, n: u32| { i.set(i.get() + n); Ok(()) }) })?; f.call::<Function>(())?.call::<()>(10)?; Ok(()) })?;
assert_eq!(i.get(), 10);
Ok(())}
#[test]fn test_scope_userdata_fields() -> Result<()> { struct MyUserData<'a>(&'a Cell<i64>);
impl UserData for MyUserData<'_> { fn register(reg: &mut UserDataRegistry<Self>) { reg.add_field("field", "hello"); reg.add_field_method_get("val", |_, data| Ok(data.0.get())); reg.add_field_method_set("val", |_, data, val| { data.0.set(val); Ok(()) }); } }
let lua = Lua::new();
let i = Cell::new(42); let f: Function = lua .load( r#" function(u) assert(u.field == "hello") assert(u.val == 42) u.val = 44 end "#, ) .eval()?;
lua.scope(|scope| f.call::<()>(scope.create_userdata(MyUserData(&i))?))?;
assert_eq!(i.get(), 44);
Ok(())}
#[test]fn test_scope_userdata_methods() -> Result<()> { struct MyUserData<'a>(&'a Cell<i64>);
impl UserData for MyUserData<'_> { fn register(reg: &mut UserDataRegistry<Self>) { reg.add_method("inc", |_, data, ()| { data.0.set(data.0.get() + 1); Ok(()) });
reg.add_method("dec", |_, data, ()| { data.0.set(data.0.get() - 1); Ok(()) }); } }
let lua = Lua::new();
let i = Cell::new(42); let f: Function = lua .load( r#" function(u) u:inc() u:inc() u:inc() u:dec() end "#, ) .eval()?;
lua.scope(|scope| f.call::<()>(scope.create_userdata(MyUserData(&i))?))?;
assert_eq!(i.get(), 44);
Ok(())}
#[test]fn test_scope_userdata_ops() -> Result<()> { struct MyUserData<'a>(&'a i64);
impl UserData for MyUserData<'_> { fn register(reg: &mut UserDataRegistry<Self>) { reg.add_meta_method(MetaMethod::Add, |lua, this, ()| { let globals = lua.globals(); globals.set("i", globals.get::<i64>("i")? + this.0)?; Ok(()) }); reg.add_meta_method(MetaMethod::Sub, |lua, this, ()| { let globals = lua.globals(); globals.set("i", globals.get::<i64>("i")? + this.0)?; Ok(()) }); } }
let lua = Lua::new();
let dummy = 1; let f = lua .load( r#" i = 0 return function(u) _ = u + u _ = u - 1 _ = u + 1 end "#, ) .eval::<Function>()?;
lua.scope(|scope| f.call::<()>(scope.create_userdata(MyUserData(&dummy))?))?;
assert_eq!(lua.globals().get::<i64>("i")?, 3);
Ok(())}
#[test]fn test_scope_userdata_values() -> Result<()> { struct MyUserData<'a>(&'a i64);
impl UserData for MyUserData<'_> { fn register(registry: &mut UserDataRegistry<Self>) { registry.add_method("get", |_, data, ()| Ok(*data.0)); } }
let lua = Lua::new();
let i = 42; let data = MyUserData(&i); lua.scope(|scope| { let ud = scope.create_userdata(data)?; assert_eq!(ud.call_method::<i64>("get", &ud)?, 42); ud.set_user_value("user_value")?; assert_eq!(ud.user_value::<String>()?, "user_value"); Ok(()) })?;
Ok(())}
#[test]fn test_scope_userdata_mismatch() -> Result<()> { struct MyUserData<'a>(&'a mut i64);
impl<'a> UserData for MyUserData<'a> { fn register(reg: &mut UserDataRegistry<Self>) { reg.add_method("get", |_, data, ()| Ok(*data.0));
reg.add_method_mut("inc", |_, data, ()| { *data.0 = data.0.wrapping_add(1); Ok(()) }); } }
let lua = Lua::new();
lua.load( r#" function inc(a, b) a.inc(b) end function get(a, b) a.get(b) end "#, ) .exec()?;
let mut a = 1; let mut b = 1;
lua.scope(|scope| { let au = scope.create_userdata(MyUserData(&mut a))?; let bu = scope.create_userdata(MyUserData(&mut b))?; for method_name in ["get", "inc"] { let f: Function = lua.globals().get(method_name)?; let full_name = format!("MyUserData.{method_name}"); let full_name = full_name.as_str();
assert!(f.call::<()>((&au, &au)).is_ok()); match f.call::<()>((&au, &bu)) { Err(Error::CallbackError { ref cause, .. }) => match cause.as_ref() { Error::BadArgument { to, pos, name, cause } => { assert_eq!(to.as_deref(), Some(full_name)); assert_eq!(*pos, 1); assert_eq!(name.as_deref(), Some("self")); assert!(matches!(*cause.as_ref(), Error::UserDataTypeMismatch)); } other => panic!("wrong error type {other:?}"), }, Err(other) => panic!("wrong error type {other:?}"), Ok(_) => panic!("incorrectly returned Ok"), }
// Pass non-userdata type let err = f.call::<()>((&au, 321)).err().unwrap(); match err { Error::CallbackError { ref cause, .. } => match cause.as_ref() { Error::BadArgument { to, pos, name, cause } => { assert_eq!(to.as_deref(), Some(full_name)); assert_eq!(*pos, 1); assert_eq!(name.as_deref(), Some("self")); assert!(matches!(*cause.as_ref(), Error::FromLuaConversionError { .. })); } other => panic!("wrong error type {other:?}"), }, other => panic!("wrong error type {other:?}"), } let err_msg = format!("bad argument `self` to `{full_name}`: error converting Lua number to userdata (expected userdata of type 'MyUserData')"); assert!(err.to_string().contains(&err_msg)); } Ok(()) })?;
Ok(())}
#[test]fn test_scope_userdata_drop() -> Result<()> { let lua = Lua::new();
struct MyUserData<'a>(&'a Cell<i64>, #[allow(unused)] Rc<()>);
impl UserData for MyUserData<'_> { fn register(reg: &mut UserDataRegistry<Self>) { reg.add_method("inc", |_, data, ()| { data.0.set(data.0.get() + 1); Ok(()) }); } }
let (i, rc) = (Cell::new(1), Rc::new(())); lua.scope(|scope| { let ud = scope.create_userdata(MyUserData(&i, rc.clone()))?; lua.globals().set("ud", ud)?; lua.load("ud:inc()").exec()?; assert_eq!(Rc::strong_count(&rc), 2); Ok(()) })?; assert_eq!(Rc::strong_count(&rc), 1); assert_eq!(i.get(), 2);
match lua.load("ud:inc()").exec() { Err(Error::CallbackError { ref cause, .. }) => match cause.as_ref() { Error::UserDataDestructed => {} err => panic!("expected UserDataDestructed, got {err:?}"), }, r => panic!("improper return for destructed userdata: {r:?}"), };
let ud = lua.globals().get::<AnyUserData>("ud")?; match ud.borrow_scoped::<MyUserData, _>(|_| Ok::<_, Error>(())) { Ok(_) => panic!("successful borrow for destructed userdata"), Err(Error::UserDataDestructed) => {} Err(err) => panic!("improper borrow error for destructed userdata: {err:?}"), } match ud.metatable() { Ok(_) => panic!("successful metatable retrieval of destructed userdata"), Err(Error::UserDataDestructed) => {} Err(err) => panic!("improper metatable error for destructed userdata: {err:?}"), }
Ok(())}
#[test]fn test_scope_userdata_ref() -> Result<()> { let lua = Lua::new();
struct MyUserData(Cell<i64>);
impl UserData for MyUserData { fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) { methods.add_method("inc", |_, data, ()| { data.0.set(data.0.get() + 1); Ok(()) });
methods.add_method("dec", |_, data, ()| { data.0.set(data.0.get() - 1); Ok(()) }); } }
let data = MyUserData(Cell::new(1)); lua.scope(|scope| { let ud = scope.create_userdata_ref(&data)?; modify_userdata(&lua, &ud)?;
// We can only borrow userdata scoped #[rustfmt::skip] assert!(matches!(ud.borrow::<MyUserData>(), Err(Error::UserDataTypeMismatch))); ud.borrow_scoped::<MyUserData, ()>(|ud_inst| { assert_eq!(ud_inst.0.get(), 2); })?;
Ok(()) })?; assert_eq!(data.0.get(), 2);
Ok(())}
#[test]fn test_scope_userdata_ref_mut() -> Result<()> { let lua = Lua::new();
struct MyUserData(i64);
impl UserData for MyUserData { fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) { methods.add_method_mut("inc", |_, data, ()| { data.0 += 1; Ok(()) });
methods.add_method_mut("dec", |_, data, ()| { data.0 -= 1; Ok(()) }); } }
let mut data = MyUserData(1); lua.scope(|scope| { let ud = scope.create_userdata_ref_mut(&mut data)?; modify_userdata(&lua, &ud)?;
#[rustfmt::skip] assert!(matches!(ud.borrow_mut::<MyUserData>(), Err(Error::UserDataTypeMismatch))); ud.borrow_mut_scoped::<MyUserData, ()>(|ud_inst| { ud_inst.0 += 10; })?;
Ok(()) })?; assert_eq!(data.0, 12);
Ok(())}
#[test]fn test_scope_any_userdata() -> Result<()> { let lua = Lua::new();
fn register(reg: &mut UserDataRegistry<&mut StdString>) { reg.add_method_mut("push", |_, this, s: String| { this.push_str(&s.to_str()?); Ok(()) }); reg.add_meta_method("__tostring", |_, data, ()| Ok((*data).clone())); }
let mut data = StdString::from("foo"); lua.scope(|scope| { let ud = scope.create_any_userdata(&mut data, register)?; lua.globals().set("ud", ud)?; lua.load( r#" assert(tostring(ud) == "foo") ud:push("bar") assert(tostring(ud) == "foobar") "#, ) .exec() })?;
// Check that userdata is destructed match lua.load("tostring(ud)").exec() { Err(Error::CallbackError { ref cause, .. }) => match cause.as_ref() { Error::UserDataDestructed => {} err => panic!("expected CallbackDestructed, got {err:?}"), }, r => panic!("improper return for destructed userdata: {r:?}"), };
Ok(())}
#[test]fn test_scope_any_userdata_ref() -> Result<()> { let lua = Lua::new();
lua.register_userdata_type::<Cell<i64>>(|reg| { reg.add_method("inc", |_, data, ()| { data.set(data.get() + 1); Ok(()) });
reg.add_method("dec", |_, data, ()| { data.set(data.get() - 1); Ok(()) }); })?;
let data = Cell::new(1i64); lua.scope(|scope| { let ud = scope.create_any_userdata_ref(&data)?; modify_userdata(&lua, &ud) })?; assert_eq!(data.get(), 2);
Ok(())}
#[test]fn test_scope_any_userdata_ref_mut() -> Result<()> { let lua = Lua::new();
lua.register_userdata_type::<i64>(|reg| { reg.add_method_mut("inc", |_, data, ()| { *data += 1; Ok(()) });
reg.add_method_mut("dec", |_, data, ()| { *data -= 1; Ok(()) }); })?;
let mut data = 1i64; lua.scope(|scope| { let ud = scope.create_any_userdata_ref_mut(&mut data)?; modify_userdata(&lua, &ud) })?; assert_eq!(data, 2);
Ok(())}
#[test]fn test_scope_destructors() -> Result<()> { let lua = Lua::new();
lua.register_userdata_type::<Arc<StdString>>(|reg| { reg.add_meta_method("__tostring", |_, data, ()| Ok(data.to_string())); })?;
let arc_str = Arc::new(StdString::from("foo"));
let ud = lua.create_any_userdata(arc_str.clone())?; lua.scope(|scope| { scope.add_destructor(|| { assert!(ud.destroy().is_ok()); }); Ok(()) })?; assert_eq!(Arc::strong_count(&arc_str), 1);
// Try destructing the userdata while it's borrowed let ud = lua.create_any_userdata(arc_str.clone())?; ud.borrow_scoped::<Arc<StdString>, _>(|arc_str| { assert_eq!(arc_str.as_str(), "foo"); lua.scope(|scope| { scope.add_destructor(|| { assert!(ud.destroy().is_err()); }); Ok(()) }) .unwrap(); assert_eq!(arc_str.as_str(), "foo"); })?;
Ok(())}
fn modify_userdata(lua: &Lua, ud: &AnyUserData) -> Result<()> { lua.load( r#" local u = ... u:inc() u:dec() u:inc()"#, ) .call(ud)}