From 3ca7b4942ed6ccad816883a2a88582705916c917 Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Sun, 4 Feb 2024 14:18:04 +0000 Subject: Implement `IntoLua` for `&Value` --- src/conversion.rs | 12 +++++++++ src/lua.rs | 70 ++++++++++++++++++++--------------------------------- tests/conversion.rs | 17 +++++++++++++ 3 files changed, 55 insertions(+), 44 deletions(-) diff --git a/src/conversion.rs b/src/conversion.rs index cb68364..d50c645 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -33,6 +33,18 @@ impl<'lua> IntoLua<'lua> for Value<'lua> { } } +impl<'lua> IntoLua<'lua> for &Value<'lua> { + #[inline] + fn into_lua(self, _: &'lua Lua) -> Result> { + Ok(self.clone()) + } + + #[inline] + unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> { + lua.push_value_ref(self) + } +} + impl<'lua> FromLua<'lua> for Value<'lua> { #[inline] fn from_lua(lua_value: Value<'lua>, _: &'lua Lua) -> Result { diff --git a/src/lua.rs b/src/lua.rs index 6597a60..9938a74 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -2269,39 +2269,38 @@ impl Lua { extra.app_data.remove() } + /// Pushes a value that implements `IntoLua` onto the Lua stack. + /// + /// Uses 2 stack spaces, does not call checkstack. #[doc(hidden)] #[inline(always)] pub unsafe fn push<'lua>(&'lua self, value: impl IntoLua<'lua>) -> Result<()> { value.push_into_stack(self) } - /// Pushes a value onto the Lua stack. + /// Pushes a `Value` onto the Lua stack. /// /// Uses 2 stack spaces, does not call checkstack. #[doc(hidden)] pub unsafe fn push_value(&self, value: Value) -> Result<()> { + if let Value::Error(err) = value { + let protect = !self.unlikely_memory_error(); + return push_gc_userdata(self.state(), WrappedFailure::Error(err), protect); + } + self.push_value_ref(&value) + } + + /// Pushes a `&Value` (by reference) onto the Lua stack. + /// + /// Similar to [`Lua::push_value`], uses 2 stack spaces, does not call checkstack. + pub(crate) unsafe fn push_value_ref(&self, value: &Value) -> Result<()> { let state = self.state(); match value { - Value::Nil => { - ffi::lua_pushnil(state); - } - - Value::Boolean(b) => { - ffi::lua_pushboolean(state, b as c_int); - } - - Value::LightUserData(ud) => { - ffi::lua_pushlightuserdata(state, ud.0); - } - - Value::Integer(i) => { - ffi::lua_pushinteger(state, i); - } - - Value::Number(n) => { - ffi::lua_pushnumber(state, n); - } - + Value::Nil => ffi::lua_pushnil(state), + Value::Boolean(b) => ffi::lua_pushboolean(state, *b as c_int), + Value::LightUserData(ud) => ffi::lua_pushlightuserdata(state, ud.0), + Value::Integer(i) => ffi::lua_pushinteger(state, *i), + Value::Number(n) => ffi::lua_pushnumber(state, *n), #[cfg(feature = "luau")] Value::Vector(v) => { #[cfg(not(feature = "luau-vector4"))] @@ -2309,33 +2308,16 @@ impl Lua { #[cfg(feature = "luau-vector4")] ffi::lua_pushvector(state, v.x(), v.y(), v.z(), v.w()); } - - Value::String(s) => { - self.push_ref(&s.0); - } - - Value::Table(t) => { - self.push_ref(&t.0); - } - - Value::Function(f) => { - self.push_ref(&f.0); - } - - Value::Thread(t) => { - self.push_ref(&t.0); - } - - Value::UserData(ud) => { - self.push_ref(&ud.0); - } - + Value::String(s) => self.push_ref(&s.0), + Value::Table(t) => self.push_ref(&t.0), + Value::Function(f) => self.push_ref(&f.0), + Value::Thread(t) => self.push_ref(&t.0), + Value::UserData(ud) => self.push_ref(&ud.0), Value::Error(err) => { let protect = !self.unlikely_memory_error(); - push_gc_userdata(state, WrappedFailure::Error(err), protect)?; + push_gc_userdata(state, WrappedFailure::Error(err.clone()), protect)?; } } - Ok(()) } diff --git a/tests/conversion.rs b/tests/conversion.rs index 4e011ed..0401b93 100644 --- a/tests/conversion.rs +++ b/tests/conversion.rs @@ -5,6 +5,23 @@ use std::ffi::{CStr, CString}; use maplit::{btreemap, btreeset, hashmap, hashset}; use mlua::{AnyUserData, Error, Function, IntoLua, Lua, Result, Table, Thread, UserDataRef, Value}; +#[test] +fn test_value_into_lua() -> Result<()> { + let lua = Lua::new(); + + // Direct conversion + let v = Value::Boolean(true); + let v2 = (&v).into_lua(&lua)?; + assert_eq!(v, v2); + + // Push into stack + let table = lua.create_table()?; + table.set("v", &v)?; + assert_eq!(v, table.get::<_, Value>("v")?); + + Ok(()) +} + #[test] fn test_string_into_lua() -> Result<()> { let lua = Lua::new(); -- cgit v1.2.3