From 143c3a81a7a648c1e7036190a8d3d0c656bd5c9f Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Sat, 30 Nov 2019 00:52:31 +0000 Subject: [PATCH] Add pair and ipair metamethods support (lua 5.2/5.3 only) --- src/userdata.rs | 14 ++++++++++++++ tests/userdata.rs | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/userdata.rs b/src/userdata.rs index 18da3b4..8177ad9 100644 --- a/src/userdata.rs +++ b/src/userdata.rs @@ -70,6 +70,16 @@ pub enum MetaMethod { /// /// This is not an operator, but will be called by methods such as `tostring` and `print`. ToString, + #[cfg(any(feature = "lua53", feature = "lua52"))] + /// The `__pairs` metamethod. + /// + /// This is not an operator, but it will be called by the built-in `pairs` function. + Pairs, + #[cfg(any(feature = "lua53", feature = "lua52"))] + /// The `__ipairs` metamethod. + /// + /// This is not an operator, but it will be called by the built-in `ipairs` function. + IPairs, } impl MetaMethod { @@ -105,6 +115,10 @@ impl MetaMethod { MetaMethod::NewIndex => b"__newindex", MetaMethod::Call => b"__call", MetaMethod::ToString => b"__tostring", + #[cfg(any(feature = "lua53", feature = "lua52"))] + MetaMethod::Pairs => b"__pairs", + #[cfg(any(feature = "lua53", feature = "lua52"))] + MetaMethod::IPairs => b"__ipairs", } } } diff --git a/tests/userdata.rs b/tests/userdata.rs index 1664468..4f01669 100644 --- a/tests/userdata.rs +++ b/tests/userdata.rs @@ -103,6 +103,18 @@ fn test_metamethods() -> Result<()> { Err("no such custom index".to_lua_err()) } }); + #[cfg(any(feature = "lua53", feature = "lua52"))] + methods.add_meta_method(MetaMethod::IPairs, |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)) + }); } } @@ -114,9 +126,29 @@ fn test_metamethods() -> Result<()> { lua.load("userdata1 + userdata2").eval::()?.0, 10 ); + + #[cfg(any(feature = "lua53", feature = "lua52"))] + let ipairs_it = { + lua.load( + r#" + function ipairs_it() + local r = 0 + for i, v in ipairs(userdata1) do + r = r + v + end + return r + end + "#, + ) + .exec()?; + globals.get::<_, Function>("ipairs_it")? + }; + assert_eq!(lua.load("userdata1 - userdata2").eval::()?.0, 4); assert_eq!(lua.load("userdata1:get()").eval::()?, 7); assert_eq!(lua.load("userdata2.inner").eval::()?, 3); + #[cfg(any(feature = "lua53", feature = "lua52"))] + assert_eq!(ipairs_it.call::<_, i64>(())?, 28); assert!(lua.load("userdata2.nonexist_field").eval::<()>().is_err()); Ok(())