Skip to content

Commit 8200bee

Browse files
committed
Implement IntoLua for ref to String/Table/Function/AnyUserData
This would prevent cloning plus has better performance when pushing values to Lua stack (`IntoLua::push_into_stack` method)
1 parent fe6ab25 commit 8200bee

File tree

8 files changed

+295
-40
lines changed

8 files changed

+295
-40
lines changed

src/conversion.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ impl<'lua> IntoLua<'lua> for String<'lua> {
4444
}
4545
}
4646

47+
impl<'lua> IntoLua<'lua> for &String<'lua> {
48+
#[inline]
49+
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
50+
Ok(Value::String(self.clone()))
51+
}
52+
53+
#[inline]
54+
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
55+
Ok(lua.push_ref(&self.0))
56+
}
57+
}
58+
4759
impl<'lua> FromLua<'lua> for String<'lua> {
4860
#[inline]
4961
fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<String<'lua>> {
@@ -64,6 +76,18 @@ impl<'lua> IntoLua<'lua> for Table<'lua> {
6476
}
6577
}
6678

79+
impl<'lua> IntoLua<'lua> for &Table<'lua> {
80+
#[inline]
81+
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
82+
Ok(Value::Table(self.clone()))
83+
}
84+
85+
#[inline]
86+
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
87+
Ok(lua.push_ref(&self.0))
88+
}
89+
}
90+
6791
impl<'lua> FromLua<'lua> for Table<'lua> {
6892
#[inline]
6993
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Table<'lua>> {
@@ -87,6 +111,20 @@ impl<'lua> IntoLua<'lua> for OwnedTable {
87111
}
88112
}
89113

114+
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
115+
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
116+
impl<'lua> IntoLua<'lua> for &OwnedTable {
117+
#[inline]
118+
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
119+
OwnedTable::into_lua(self.clone(), lua)
120+
}
121+
122+
#[inline]
123+
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
124+
Ok(lua.push_owned_ref(&self.0))
125+
}
126+
}
127+
90128
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
91129
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
92130
impl<'lua> FromLua<'lua> for OwnedTable {
@@ -103,6 +141,18 @@ impl<'lua> IntoLua<'lua> for Function<'lua> {
103141
}
104142
}
105143

144+
impl<'lua> IntoLua<'lua> for &Function<'lua> {
145+
#[inline]
146+
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
147+
Ok(Value::Function(self.clone()))
148+
}
149+
150+
#[inline]
151+
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
152+
Ok(lua.push_ref(&self.0))
153+
}
154+
}
155+
106156
impl<'lua> FromLua<'lua> for Function<'lua> {
107157
#[inline]
108158
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Function<'lua>> {
@@ -126,6 +176,20 @@ impl<'lua> IntoLua<'lua> for OwnedFunction {
126176
}
127177
}
128178

179+
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
180+
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
181+
impl<'lua> IntoLua<'lua> for &OwnedFunction {
182+
#[inline]
183+
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
184+
OwnedFunction::into_lua(self.clone(), lua)
185+
}
186+
187+
#[inline]
188+
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
189+
Ok(lua.push_owned_ref(&self.0))
190+
}
191+
}
192+
129193
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
130194
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
131195
impl<'lua> FromLua<'lua> for OwnedFunction {
@@ -142,6 +206,18 @@ impl<'lua> IntoLua<'lua> for Thread<'lua> {
142206
}
143207
}
144208

209+
impl<'lua> IntoLua<'lua> for &Thread<'lua> {
210+
#[inline]
211+
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
212+
Ok(Value::Thread(self.clone()))
213+
}
214+
215+
#[inline]
216+
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
217+
Ok(lua.push_ref(&self.0))
218+
}
219+
}
220+
145221
impl<'lua> FromLua<'lua> for Thread<'lua> {
146222
#[inline]
147223
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Thread<'lua>> {
@@ -163,6 +239,18 @@ impl<'lua> IntoLua<'lua> for AnyUserData<'lua> {
163239
}
164240
}
165241

242+
impl<'lua> IntoLua<'lua> for &AnyUserData<'lua> {
243+
#[inline]
244+
fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
245+
Ok(Value::UserData(self.clone()))
246+
}
247+
248+
#[inline]
249+
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
250+
Ok(lua.push_ref(&self.0))
251+
}
252+
}
253+
166254
impl<'lua> FromLua<'lua> for AnyUserData<'lua> {
167255
#[inline]
168256
fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<AnyUserData<'lua>> {
@@ -189,6 +277,20 @@ impl<'lua> IntoLua<'lua> for OwnedAnyUserData {
189277
}
190278
}
191279

280+
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
281+
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
282+
impl<'lua> IntoLua<'lua> for &OwnedAnyUserData {
283+
#[inline]
284+
fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
285+
OwnedAnyUserData::into_lua(self.clone(), lua)
286+
}
287+
288+
#[inline]
289+
unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
290+
Ok(lua.push_owned_ref(&self.0))
291+
}
292+
}
293+
192294
#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
193295
#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
194296
impl<'lua> FromLua<'lua> for OwnedAnyUserData {

src/lua.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2558,6 +2558,15 @@ impl Lua {
25582558
ffi::lua_xpush(self.ref_thread(), self.state(), lref.index);
25592559
}
25602560

2561+
#[cfg(all(feature = "unstable", not(feature = "send")))]
2562+
pub(crate) unsafe fn push_owned_ref(&self, loref: &crate::types::LuaOwnedRef) {
2563+
assert!(
2564+
Arc::ptr_eq(&loref.inner, &self.0),
2565+
"Lua instance passed Value created from a different main Lua state"
2566+
);
2567+
ffi::lua_xpush(self.ref_thread(), self.state(), loref.index);
2568+
}
2569+
25612570
// Pops the topmost element of the stack and stores a reference to it. This pins the object,
25622571
// preventing garbage collection until the returned `LuaRef` is dropped.
25632572
//

tests/async.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ async fn test_async_userdata() -> Result<()> {
443443
let globals = lua.globals();
444444

445445
let userdata = lua.create_userdata(MyUserData(11))?;
446-
globals.set("userdata", userdata.clone())?;
446+
globals.set("userdata", &userdata)?;
447447

448448
lua.load(
449449
r#"

tests/conversion.rs

Lines changed: 174 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,180 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
33
use std::ffi::{CStr, CString};
44

55
use maplit::{btreemap, btreeset, hashmap, hashset};
6-
use mlua::{Error, Lua, Result};
6+
use mlua::{AnyUserData, Error, Function, IntoLua, Lua, Result, Table, Thread, UserDataRef, Value};
7+
8+
#[test]
9+
fn test_string_into_lua() -> Result<()> {
10+
let lua = Lua::new();
11+
12+
// Direct conversion
13+
let s = lua.create_string("hello, world!")?;
14+
let s2 = (&s).into_lua(&lua)?;
15+
assert_eq!(s, s2.as_string().unwrap());
16+
17+
// Push into stack
18+
let table = lua.create_table()?;
19+
table.set("s", &s)?;
20+
assert_eq!(s, table.get::<_, String>("s")?);
21+
22+
Ok(())
23+
}
24+
25+
#[test]
26+
fn test_table_into_lua() -> Result<()> {
27+
let lua = Lua::new();
28+
29+
// Direct conversion
30+
let t = lua.create_table()?;
31+
let t2 = (&t).into_lua(&lua)?;
32+
assert_eq!(&t, t2.as_table().unwrap());
33+
34+
// Push into stack
35+
let f = lua.create_function(|_, (t, s): (Table, String)| t.set("s", s))?;
36+
f.call((&t, "hello"))?;
37+
assert_eq!("hello", t.get::<_, String>("s")?);
38+
39+
Ok(())
40+
}
41+
42+
#[cfg(all(feature = "unstable", not(feature = "send")))]
43+
#[test]
44+
fn test_owned_table_into_lua() -> Result<()> {
45+
let lua = Lua::new();
46+
47+
// Direct conversion
48+
let t = lua.create_table()?.into_owned();
49+
let t2 = (&t).into_lua(&lua)?;
50+
assert_eq!(t.to_ref(), *t2.as_table().unwrap());
51+
52+
// Push into stack
53+
let f = lua.create_function(|_, (t, s): (Table, String)| t.set("s", s))?;
54+
f.call((&t, "hello"))?;
55+
assert_eq!("hello", t.to_ref().get::<_, String>("s")?);
56+
57+
Ok(())
58+
}
59+
60+
#[test]
61+
fn test_function_into_lua() -> Result<()> {
62+
let lua = Lua::new();
63+
64+
// Direct conversion
65+
let f = lua.create_function(|_, ()| Ok::<_, Error>(()))?;
66+
let f2 = (&f).into_lua(&lua)?;
67+
assert_eq!(&f, f2.as_function().unwrap());
68+
69+
// Push into stack
70+
let table = lua.create_table()?;
71+
table.set("f", &f)?;
72+
assert_eq!(f, table.get::<_, Function>("f")?);
73+
74+
Ok(())
75+
}
76+
77+
#[cfg(all(feature = "unstable", not(feature = "send")))]
78+
#[test]
79+
fn test_owned_function_into_lua() -> Result<()> {
80+
let lua = Lua::new();
81+
82+
// Direct conversion
83+
let f = lua
84+
.create_function(|_, ()| Ok::<_, Error>(()))?
85+
.into_owned();
86+
let f2 = (&f).into_lua(&lua)?;
87+
assert_eq!(f.to_ref(), *f2.as_function().unwrap());
88+
89+
// Push into stack
90+
let table = lua.create_table()?;
91+
table.set("f", &f)?;
92+
assert_eq!(f.to_ref(), table.get::<_, Function>("f")?);
93+
94+
Ok(())
95+
}
96+
97+
#[test]
98+
fn test_thread_into_lua() -> Result<()> {
99+
let lua = Lua::new();
100+
101+
// Direct conversion
102+
let f = lua.create_function(|_, ()| Ok::<_, Error>(()))?;
103+
let th = lua.create_thread(f)?;
104+
let th2 = (&th).into_lua(&lua)?;
105+
assert_eq!(&th, th2.as_thread().unwrap());
106+
107+
// Push into stack
108+
let table = lua.create_table()?;
109+
table.set("th", &th)?;
110+
assert_eq!(th, table.get::<_, Thread>("th")?);
111+
112+
Ok(())
113+
}
114+
115+
#[test]
116+
fn test_anyuserdata_into_lua() -> Result<()> {
117+
let lua = Lua::new();
118+
119+
// Direct conversion
120+
let ud = lua.create_any_userdata(String::from("hello"))?;
121+
let ud2 = (&ud).into_lua(&lua)?;
122+
assert_eq!(&ud, ud2.as_userdata().unwrap());
123+
124+
// Push into stack
125+
let table = lua.create_table()?;
126+
table.set("ud", &ud)?;
127+
assert_eq!(ud, table.get::<_, AnyUserData>("ud")?);
128+
assert_eq!("hello", *table.get::<_, UserDataRef<String>>("ud")?);
129+
130+
Ok(())
131+
}
132+
133+
#[cfg(all(feature = "unstable", not(feature = "send")))]
134+
#[test]
135+
fn test_owned_anyuserdata_into_lua() -> Result<()> {
136+
let lua = Lua::new();
137+
138+
// Direct conversion
139+
let ud = lua.create_any_userdata(String::from("hello"))?.into_owned();
140+
let ud2 = (&ud).into_lua(&lua)?;
141+
assert_eq!(ud.to_ref(), *ud2.as_userdata().unwrap());
142+
143+
// Push into stack
144+
let table = lua.create_table()?;
145+
table.set("ud", &ud)?;
146+
assert_eq!(ud.to_ref(), table.get::<_, AnyUserData>("ud")?);
147+
assert_eq!("hello", *table.get::<_, UserDataRef<String>>("ud")?);
148+
149+
Ok(())
150+
}
151+
152+
#[test]
153+
fn test_registry_value_into_lua() -> Result<()> {
154+
let lua = Lua::new();
155+
156+
let t = lua.create_table()?;
157+
let r = lua.create_registry_value(t)?;
158+
let f = lua.create_function(|_, t: Table| t.raw_set("hello", "world"))?;
159+
160+
f.call(&r)?;
161+
let v = r.into_lua(&lua)?;
162+
let t = v.as_table().unwrap();
163+
assert_eq!(t.get::<_, String>("hello")?, "world");
164+
165+
// Try to set nil registry key
166+
let r_nil = lua.create_registry_value(Value::Nil)?;
167+
t.set("hello", &r_nil)?;
168+
assert_eq!(t.get::<_, Value>("hello")?, Value::Nil);
169+
170+
// Check non-owned registry key
171+
let lua2 = Lua::new();
172+
let r2 = lua2.create_registry_value("abc")?;
173+
assert!(matches!(
174+
f.call::<_, ()>(&r2),
175+
Err(Error::MismatchedRegistryKey)
176+
));
177+
178+
Ok(())
179+
}
7180

8181
#[test]
9182
fn test_conv_vec() -> Result<()> {

tests/serde.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ fn test_from_value_with_options() -> Result<(), Box<dyn StdError>> {
598598

599599
// Check recursion when using `Serialize` impl
600600
let t = lua.create_table()?;
601-
t.set("t", t.clone())?;
601+
t.set("t", &t)?;
602602
assert!(serde_json::to_string(&t).is_err());
603603

604604
// Serialize Lua globals table

0 commit comments

Comments
 (0)