mlua/
conversion.rs

1use std::borrow::Cow;
2use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
3use std::ffi::{CStr, CString};
4use std::hash::{BuildHasher, Hash};
5use std::os::raw::c_int;
6use std::string::String as StdString;
7use std::{slice, str};
8
9use bstr::{BStr, BString};
10use num_traits::cast;
11
12use crate::error::{Error, Result};
13use crate::function::Function;
14use crate::lua::Lua;
15use crate::string::String;
16use crate::table::Table;
17use crate::thread::Thread;
18use crate::types::{LightUserData, MaybeSend, RegistryKey};
19use crate::userdata::{AnyUserData, UserData, UserDataRef, UserDataRefMut};
20use crate::value::{FromLua, IntoLua, Nil, Value};
21
22#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
23use crate::{
24    function::OwnedFunction, string::OwnedString, table::OwnedTable, thread::OwnedThread,
25    userdata::OwnedAnyUserData,
26};
27
28impl<'lua> IntoLua<'lua> for Value<'lua> {
29    #[inline]
30    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
31        Ok(self)
32    }
33}
34
35impl<'lua> IntoLua<'lua> for &Value<'lua> {
36    #[inline]
37    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
38        Ok(self.clone())
39    }
40
41    #[inline]
42    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
43        lua.push_value_ref(self)
44    }
45}
46
47impl<'lua> FromLua<'lua> for Value<'lua> {
48    #[inline]
49    fn from_lua(lua_value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
50        Ok(lua_value)
51    }
52}
53
54impl<'lua> IntoLua<'lua> for String<'lua> {
55    #[inline]
56    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
57        Ok(Value::String(self))
58    }
59}
60
61impl<'lua> IntoLua<'lua> for &String<'lua> {
62    #[inline]
63    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
64        Ok(Value::String(self.clone()))
65    }
66
67    #[inline]
68    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
69        lua.push_ref(&self.0);
70        Ok(())
71    }
72}
73
74impl<'lua> FromLua<'lua> for String<'lua> {
75    #[inline]
76    fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<String<'lua>> {
77        let ty = value.type_name();
78        lua.coerce_string(value)?
79            .ok_or_else(|| Error::FromLuaConversionError {
80                from: ty,
81                to: "string",
82                message: Some("expected string or number".to_string()),
83            })
84    }
85}
86
87#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
88#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
89impl<'lua> IntoLua<'lua> for OwnedString {
90    #[inline]
91    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
92        Ok(Value::String(String(lua.adopt_owned_ref(self.0))))
93    }
94}
95
96#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
97#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
98impl<'lua> IntoLua<'lua> for &OwnedString {
99    #[inline]
100    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
101        OwnedString::into_lua(self.clone(), lua)
102    }
103
104    #[inline]
105    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
106        lua.push_owned_ref(&self.0);
107        Ok(())
108    }
109}
110
111#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
112#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
113impl<'lua> FromLua<'lua> for OwnedString {
114    #[inline]
115    fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<OwnedString> {
116        String::from_lua(value, lua).map(|s| s.into_owned())
117    }
118}
119
120impl<'lua> IntoLua<'lua> for Table<'lua> {
121    #[inline]
122    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
123        Ok(Value::Table(self))
124    }
125}
126
127impl<'lua> IntoLua<'lua> for &Table<'lua> {
128    #[inline]
129    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
130        Ok(Value::Table(self.clone()))
131    }
132
133    #[inline]
134    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
135        lua.push_ref(&self.0);
136        Ok(())
137    }
138}
139
140impl<'lua> FromLua<'lua> for Table<'lua> {
141    #[inline]
142    fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Table<'lua>> {
143        match value {
144            Value::Table(table) => Ok(table),
145            _ => Err(Error::FromLuaConversionError {
146                from: value.type_name(),
147                to: "table",
148                message: None,
149            }),
150        }
151    }
152}
153
154#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
155#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
156impl<'lua> IntoLua<'lua> for OwnedTable {
157    #[inline]
158    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
159        Ok(Value::Table(Table(lua.adopt_owned_ref(self.0))))
160    }
161}
162
163#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
164#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
165impl<'lua> IntoLua<'lua> for &OwnedTable {
166    #[inline]
167    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
168        OwnedTable::into_lua(self.clone(), lua)
169    }
170
171    #[inline]
172    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
173        lua.push_owned_ref(&self.0);
174        Ok(())
175    }
176}
177
178#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
179#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
180impl<'lua> FromLua<'lua> for OwnedTable {
181    #[inline]
182    fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<OwnedTable> {
183        Table::from_lua(value, lua).map(|s| s.into_owned())
184    }
185}
186
187impl<'lua> IntoLua<'lua> for Function<'lua> {
188    #[inline]
189    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
190        Ok(Value::Function(self))
191    }
192}
193
194impl<'lua> IntoLua<'lua> for &Function<'lua> {
195    #[inline]
196    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
197        Ok(Value::Function(self.clone()))
198    }
199
200    #[inline]
201    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
202        lua.push_ref(&self.0);
203        Ok(())
204    }
205}
206
207impl<'lua> FromLua<'lua> for Function<'lua> {
208    #[inline]
209    fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Function<'lua>> {
210        match value {
211            Value::Function(table) => Ok(table),
212            _ => Err(Error::FromLuaConversionError {
213                from: value.type_name(),
214                to: "function",
215                message: None,
216            }),
217        }
218    }
219}
220
221#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
222#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
223impl<'lua> IntoLua<'lua> for OwnedFunction {
224    #[inline]
225    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
226        Ok(Value::Function(Function(lua.adopt_owned_ref(self.0))))
227    }
228}
229
230#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
231#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
232impl<'lua> IntoLua<'lua> for &OwnedFunction {
233    #[inline]
234    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
235        OwnedFunction::into_lua(self.clone(), lua)
236    }
237
238    #[inline]
239    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
240        lua.push_owned_ref(&self.0);
241        Ok(())
242    }
243}
244
245#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
246#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
247impl<'lua> FromLua<'lua> for OwnedFunction {
248    #[inline]
249    fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<OwnedFunction> {
250        Function::from_lua(value, lua).map(|s| s.into_owned())
251    }
252}
253
254impl<'lua> IntoLua<'lua> for Thread<'lua> {
255    #[inline]
256    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
257        Ok(Value::Thread(self))
258    }
259}
260
261impl<'lua> IntoLua<'lua> for &Thread<'lua> {
262    #[inline]
263    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
264        Ok(Value::Thread(self.clone()))
265    }
266
267    #[inline]
268    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
269        lua.push_ref(&self.0);
270        Ok(())
271    }
272}
273
274impl<'lua> FromLua<'lua> for Thread<'lua> {
275    #[inline]
276    fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Thread<'lua>> {
277        match value {
278            Value::Thread(t) => Ok(t),
279            _ => Err(Error::FromLuaConversionError {
280                from: value.type_name(),
281                to: "thread",
282                message: None,
283            }),
284        }
285    }
286}
287
288#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
289#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
290impl<'lua> IntoLua<'lua> for OwnedThread {
291    #[inline]
292    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
293        Ok(Value::Thread(Thread(lua.adopt_owned_ref(self.0), self.1)))
294    }
295}
296
297#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
298#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
299impl<'lua> IntoLua<'lua> for &OwnedThread {
300    #[inline]
301    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
302        OwnedThread::into_lua(self.clone(), lua)
303    }
304
305    #[inline]
306    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
307        lua.push_owned_ref(&self.0);
308        Ok(())
309    }
310}
311
312#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
313#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
314impl<'lua> FromLua<'lua> for OwnedThread {
315    #[inline]
316    fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<OwnedThread> {
317        Thread::from_lua(value, lua).map(|s| s.into_owned())
318    }
319}
320
321impl<'lua> IntoLua<'lua> for AnyUserData<'lua> {
322    #[inline]
323    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
324        Ok(Value::UserData(self))
325    }
326}
327
328impl<'lua> IntoLua<'lua> for &AnyUserData<'lua> {
329    #[inline]
330    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
331        Ok(Value::UserData(self.clone()))
332    }
333
334    #[inline]
335    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
336        lua.push_ref(&self.0);
337        Ok(())
338    }
339}
340
341impl<'lua> FromLua<'lua> for AnyUserData<'lua> {
342    #[inline]
343    fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<AnyUserData<'lua>> {
344        match value {
345            Value::UserData(ud) => Ok(ud),
346            _ => Err(Error::FromLuaConversionError {
347                from: value.type_name(),
348                to: "userdata",
349                message: None,
350            }),
351        }
352    }
353}
354
355#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
356#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
357impl<'lua> IntoLua<'lua> for OwnedAnyUserData {
358    #[inline]
359    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
360        Ok(Value::UserData(AnyUserData(
361            lua.adopt_owned_ref(self.0),
362            self.1,
363        )))
364    }
365}
366
367#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
368#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
369impl<'lua> IntoLua<'lua> for &OwnedAnyUserData {
370    #[inline]
371    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
372        OwnedAnyUserData::into_lua(self.clone(), lua)
373    }
374
375    #[inline]
376    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
377        lua.push_owned_ref(&self.0);
378        Ok(())
379    }
380}
381
382#[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
383#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
384impl<'lua> FromLua<'lua> for OwnedAnyUserData {
385    #[inline]
386    fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<OwnedAnyUserData> {
387        AnyUserData::from_lua(value, lua).map(|s| s.into_owned())
388    }
389}
390
391impl<'lua, T: UserData + MaybeSend + 'static> IntoLua<'lua> for T {
392    #[inline]
393    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
394        Ok(Value::UserData(lua.create_userdata(self)?))
395    }
396}
397
398impl<'lua, T: 'static> FromLua<'lua> for UserDataRef<'lua, T> {
399    #[inline]
400    fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
401        Self::from_value(value)
402    }
403}
404
405impl<'lua, T: 'static> FromLua<'lua> for UserDataRefMut<'lua, T> {
406    #[inline]
407    fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
408        Self::from_value(value)
409    }
410}
411
412impl<'lua> IntoLua<'lua> for Error {
413    #[inline]
414    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
415        Ok(Value::Error(self))
416    }
417}
418
419impl<'lua> FromLua<'lua> for Error {
420    #[inline]
421    fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Error> {
422        match value {
423            Value::Error(err) => Ok(err),
424            val => Ok(Error::runtime(
425                lua.coerce_string(val)?
426                    .and_then(|s| Some(s.to_str().ok()?.to_owned()))
427                    .unwrap_or_else(|| "<unprintable error>".to_owned()),
428            )),
429        }
430    }
431}
432
433impl<'lua> IntoLua<'lua> for RegistryKey {
434    #[inline]
435    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
436        lua.registry_value(&self)
437    }
438
439    #[inline]
440    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
441        <&RegistryKey>::push_into_stack(&self, lua)
442    }
443}
444
445impl<'lua> IntoLua<'lua> for &RegistryKey {
446    #[inline]
447    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
448        lua.registry_value(self)
449    }
450
451    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
452        if !lua.owns_registry_value(self) {
453            return Err(Error::MismatchedRegistryKey);
454        }
455
456        match self.id() {
457            ffi::LUA_REFNIL => ffi::lua_pushnil(lua.state()),
458            id => {
459                ffi::lua_rawgeti(lua.state(), ffi::LUA_REGISTRYINDEX, id as _);
460            }
461        }
462        Ok(())
463    }
464}
465
466impl<'lua> FromLua<'lua> for RegistryKey {
467    #[inline]
468    fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<RegistryKey> {
469        lua.create_registry_value(value)
470    }
471}
472
473impl<'lua> IntoLua<'lua> for bool {
474    #[inline]
475    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
476        Ok(Value::Boolean(self))
477    }
478
479    #[inline]
480    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
481        ffi::lua_pushboolean(lua.state(), self as c_int);
482        Ok(())
483    }
484}
485
486impl<'lua> FromLua<'lua> for bool {
487    #[inline]
488    fn from_lua(v: Value<'lua>, _: &'lua Lua) -> Result<Self> {
489        match v {
490            Value::Nil => Ok(false),
491            Value::Boolean(b) => Ok(b),
492            _ => Ok(true),
493        }
494    }
495
496    #[inline]
497    unsafe fn from_stack(idx: c_int, lua: &'lua Lua) -> Result<Self> {
498        Ok(ffi::lua_toboolean(lua.state(), idx) != 0)
499    }
500}
501
502impl<'lua> IntoLua<'lua> for LightUserData {
503    #[inline]
504    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
505        Ok(Value::LightUserData(self))
506    }
507}
508
509impl<'lua> FromLua<'lua> for LightUserData {
510    #[inline]
511    fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
512        match value {
513            Value::LightUserData(ud) => Ok(ud),
514            _ => Err(Error::FromLuaConversionError {
515                from: value.type_name(),
516                to: "light userdata",
517                message: None,
518            }),
519        }
520    }
521}
522
523#[cfg(feature = "luau")]
524impl<'lua> IntoLua<'lua> for crate::types::Vector {
525    #[inline]
526    fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
527        Ok(Value::Vector(self))
528    }
529}
530
531#[cfg(feature = "luau")]
532impl<'lua> FromLua<'lua> for crate::types::Vector {
533    #[inline]
534    fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
535        match value {
536            Value::Vector(v) => Ok(v),
537            _ => Err(Error::FromLuaConversionError {
538                from: value.type_name(),
539                to: "vector",
540                message: None,
541            }),
542        }
543    }
544}
545
546impl<'lua> IntoLua<'lua> for StdString {
547    #[inline]
548    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
549        Ok(Value::String(lua.create_string(&self)?))
550    }
551
552    #[inline]
553    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
554        push_bytes_into_stack(self, lua)
555    }
556}
557
558impl<'lua> FromLua<'lua> for StdString {
559    #[inline]
560    fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
561        let ty = value.type_name();
562        Ok(lua
563            .coerce_string(value)?
564            .ok_or_else(|| Error::FromLuaConversionError {
565                from: ty,
566                to: "String",
567                message: Some("expected string or number".to_string()),
568            })?
569            .to_str()?
570            .to_owned())
571    }
572
573    #[inline]
574    unsafe fn from_stack(idx: c_int, lua: &'lua Lua) -> Result<Self> {
575        let state = lua.state();
576        if ffi::lua_type(state, idx) == ffi::LUA_TSTRING {
577            let mut size = 0;
578            let data = ffi::lua_tolstring(state, idx, &mut size);
579            let bytes = slice::from_raw_parts(data as *const u8, size);
580            return str::from_utf8(bytes).map(|s| s.to_owned()).map_err(|e| {
581                Error::FromLuaConversionError {
582                    from: "string",
583                    to: "String",
584                    message: Some(e.to_string()),
585                }
586            });
587        }
588        // Fallback to default
589        Self::from_lua(lua.stack_value(idx), lua)
590    }
591}
592
593impl<'lua> IntoLua<'lua> for &str {
594    #[inline]
595    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
596        Ok(Value::String(lua.create_string(self)?))
597    }
598
599    #[inline]
600    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
601        push_bytes_into_stack(self, lua)
602    }
603}
604
605impl<'lua> IntoLua<'lua> for Cow<'_, str> {
606    #[inline]
607    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
608        Ok(Value::String(lua.create_string(self.as_bytes())?))
609    }
610}
611
612impl<'lua> IntoLua<'lua> for Box<str> {
613    #[inline]
614    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
615        Ok(Value::String(lua.create_string(&*self)?))
616    }
617}
618
619impl<'lua> FromLua<'lua> for Box<str> {
620    #[inline]
621    fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
622        let ty = value.type_name();
623        Ok(lua
624            .coerce_string(value)?
625            .ok_or_else(|| Error::FromLuaConversionError {
626                from: ty,
627                to: "Box<str>",
628                message: Some("expected string or number".to_string()),
629            })?
630            .to_str()?
631            .to_owned()
632            .into_boxed_str())
633    }
634}
635
636impl<'lua> IntoLua<'lua> for CString {
637    #[inline]
638    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
639        Ok(Value::String(lua.create_string(self.as_bytes())?))
640    }
641}
642
643impl<'lua> FromLua<'lua> for CString {
644    #[inline]
645    fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
646        let ty = value.type_name();
647        let string = lua
648            .coerce_string(value)?
649            .ok_or_else(|| Error::FromLuaConversionError {
650                from: ty,
651                to: "CString",
652                message: Some("expected string or number".to_string()),
653            })?;
654
655        match CStr::from_bytes_with_nul(string.as_bytes_with_nul()) {
656            Ok(s) => Ok(s.into()),
657            Err(_) => Err(Error::FromLuaConversionError {
658                from: ty,
659                to: "CString",
660                message: Some("invalid C-style string".to_string()),
661            }),
662        }
663    }
664}
665
666impl<'lua> IntoLua<'lua> for &CStr {
667    #[inline]
668    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
669        Ok(Value::String(lua.create_string(self.to_bytes())?))
670    }
671}
672
673impl<'lua> IntoLua<'lua> for Cow<'_, CStr> {
674    #[inline]
675    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
676        Ok(Value::String(lua.create_string(self.to_bytes())?))
677    }
678}
679
680impl<'lua> IntoLua<'lua> for BString {
681    #[inline]
682    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
683        Ok(Value::String(lua.create_string(&self)?))
684    }
685}
686
687impl<'lua> FromLua<'lua> for BString {
688    fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
689        let ty = value.type_name();
690        match value {
691            Value::String(s) => Ok(s.as_bytes().into()),
692            #[cfg(feature = "luau")]
693            Value::UserData(ud) if ud.1 == crate::types::SubtypeId::Buffer => unsafe {
694                let mut size = 0usize;
695                let buf = ffi::lua_tobuffer(ud.0.lua.ref_thread(), ud.0.index, &mut size);
696                mlua_assert!(!buf.is_null(), "invalid Luau buffer");
697                Ok(slice::from_raw_parts(buf as *const u8, size).into())
698            },
699            _ => Ok(lua
700                .coerce_string(value)?
701                .ok_or_else(|| Error::FromLuaConversionError {
702                    from: ty,
703                    to: "BString",
704                    message: Some("expected string or number".to_string()),
705                })?
706                .as_bytes()
707                .into()),
708        }
709    }
710
711    unsafe fn from_stack(idx: c_int, lua: &'lua Lua) -> Result<Self> {
712        let state = lua.state();
713        match ffi::lua_type(state, idx) {
714            ffi::LUA_TSTRING => {
715                let mut size = 0;
716                let data = ffi::lua_tolstring(state, idx, &mut size);
717                Ok(slice::from_raw_parts(data as *const u8, size).into())
718            }
719            #[cfg(feature = "luau")]
720            ffi::LUA_TBUFFER => {
721                let mut size = 0;
722                let buf = ffi::lua_tobuffer(state, idx, &mut size);
723                mlua_assert!(!buf.is_null(), "invalid Luau buffer");
724                Ok(slice::from_raw_parts(buf as *const u8, size).into())
725            }
726            _ => {
727                // Fallback to default
728                Self::from_lua(lua.stack_value(idx), lua)
729            }
730        }
731    }
732}
733
734impl<'lua> IntoLua<'lua> for &BStr {
735    #[inline]
736    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
737        Ok(Value::String(lua.create_string(self)?))
738    }
739}
740
741#[inline]
742unsafe fn push_bytes_into_stack<'lua, T>(this: T, lua: &'lua Lua) -> Result<()>
743where
744    T: IntoLua<'lua> + AsRef<[u8]>,
745{
746    let bytes = this.as_ref();
747    if lua.unlikely_memory_error() && bytes.len() < (1 << 30) {
748        // Fast path: push directly into the Lua stack.
749        ffi::lua_pushlstring(lua.state(), bytes.as_ptr() as *const _, bytes.len());
750        return Ok(());
751    }
752    // Fallback to default
753    lua.push_value(T::into_lua(this, lua)?)
754}
755
756macro_rules! lua_convert_int {
757    ($x:ty) => {
758        impl<'lua> IntoLua<'lua> for $x {
759            #[inline]
760            fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
761                cast(self)
762                    .map(Value::Integer)
763                    .or_else(|| cast(self).map(Value::Number))
764                    // This is impossible error because conversion to Number never fails
765                    .ok_or_else(|| Error::ToLuaConversionError {
766                        from: stringify!($x),
767                        to: "number",
768                        message: Some("out of range".to_owned()),
769                    })
770            }
771
772            #[inline]
773            unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
774                match cast(self) {
775                    Some(i) => ffi::lua_pushinteger(lua.state(), i),
776                    None => ffi::lua_pushnumber(lua.state(), self as ffi::lua_Number),
777                }
778                Ok(())
779            }
780        }
781
782        impl<'lua> FromLua<'lua> for $x {
783            #[inline]
784            fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
785                let ty = value.type_name();
786                (match value {
787                    Value::Integer(i) => cast(i),
788                    Value::Number(n) => cast(n),
789                    _ => {
790                        if let Some(i) = lua.coerce_integer(value.clone())? {
791                            cast(i)
792                        } else {
793                            cast(lua.coerce_number(value)?.ok_or_else(|| {
794                                Error::FromLuaConversionError {
795                                    from: ty,
796                                    to: stringify!($x),
797                                    message: Some(
798                                        "expected number or string coercible to number".to_string(),
799                                    ),
800                                }
801                            })?)
802                        }
803                    }
804                })
805                .ok_or_else(|| Error::FromLuaConversionError {
806                    from: ty,
807                    to: stringify!($x),
808                    message: Some("out of range".to_owned()),
809                })
810            }
811        }
812    };
813}
814
815lua_convert_int!(i8);
816lua_convert_int!(u8);
817lua_convert_int!(i16);
818lua_convert_int!(u16);
819lua_convert_int!(i32);
820lua_convert_int!(u32);
821lua_convert_int!(i64);
822lua_convert_int!(u64);
823lua_convert_int!(i128);
824lua_convert_int!(u128);
825lua_convert_int!(isize);
826lua_convert_int!(usize);
827
828macro_rules! lua_convert_float {
829    ($x:ty) => {
830        impl<'lua> IntoLua<'lua> for $x {
831            #[inline]
832            fn into_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
833                cast(self)
834                    .ok_or_else(|| Error::ToLuaConversionError {
835                        from: stringify!($x),
836                        to: "number",
837                        message: Some("out of range".to_string()),
838                    })
839                    .map(Value::Number)
840            }
841        }
842
843        impl<'lua> FromLua<'lua> for $x {
844            #[inline]
845            fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
846                let ty = value.type_name();
847                lua.coerce_number(value)?
848                    .ok_or_else(|| Error::FromLuaConversionError {
849                        from: ty,
850                        to: stringify!($x),
851                        message: Some("expected number or string coercible to number".to_string()),
852                    })
853                    .and_then(|n| {
854                        cast(n).ok_or_else(|| Error::FromLuaConversionError {
855                            from: ty,
856                            to: stringify!($x),
857                            message: Some("number out of range".to_string()),
858                        })
859                    })
860            }
861        }
862    };
863}
864
865lua_convert_float!(f32);
866lua_convert_float!(f64);
867
868impl<'lua, T> IntoLua<'lua> for &[T]
869where
870    T: IntoLua<'lua> + Clone,
871{
872    #[inline]
873    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
874        Ok(Value::Table(
875            lua.create_sequence_from(self.iter().cloned())?,
876        ))
877    }
878}
879
880impl<'lua, T, const N: usize> IntoLua<'lua> for [T; N]
881where
882    T: IntoLua<'lua>,
883{
884    #[inline]
885    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
886        Ok(Value::Table(lua.create_sequence_from(self)?))
887    }
888}
889
890impl<'lua, T, const N: usize> FromLua<'lua> for [T; N]
891where
892    T: FromLua<'lua>,
893{
894    #[inline]
895    fn from_lua(value: Value<'lua>, _lua: &'lua Lua) -> Result<Self> {
896        match value {
897            #[cfg(feature = "luau")]
898            #[rustfmt::skip]
899            Value::Vector(v) if N == crate::types::Vector::SIZE => unsafe {
900                use std::{mem, ptr};
901                let mut arr: [mem::MaybeUninit<T>; N] = mem::MaybeUninit::uninit().assume_init();
902                ptr::write(arr[0].as_mut_ptr() , T::from_lua(Value::Number(v.x() as _), _lua)?);
903                ptr::write(arr[1].as_mut_ptr(), T::from_lua(Value::Number(v.y() as _), _lua)?);
904                ptr::write(arr[2].as_mut_ptr(), T::from_lua(Value::Number(v.z() as _), _lua)?);
905                #[cfg(feature = "luau-vector4")]
906                ptr::write(arr[3].as_mut_ptr(), T::from_lua(Value::Number(v.w() as _), _lua)?);
907                Ok(mem::transmute_copy(&arr))
908            },
909            Value::Table(table) => {
910                let vec = table.sequence_values().collect::<Result<Vec<_>>>()?;
911                vec.try_into()
912                    .map_err(|vec: Vec<T>| Error::FromLuaConversionError {
913                        from: "table",
914                        to: "Array",
915                        message: Some(format!("expected table of length {}, got {}", N, vec.len())),
916                    })
917            }
918            _ => Err(Error::FromLuaConversionError {
919                from: value.type_name(),
920                to: "Array",
921                message: Some("expected table".to_string()),
922            }),
923        }
924    }
925}
926
927impl<'lua, T: IntoLua<'lua>> IntoLua<'lua> for Box<[T]> {
928    #[inline]
929    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
930        Ok(Value::Table(lua.create_sequence_from(self.into_vec())?))
931    }
932}
933
934impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Box<[T]> {
935    #[inline]
936    fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
937        Ok(Vec::<T>::from_lua(value, lua)?.into_boxed_slice())
938    }
939}
940
941impl<'lua, T: IntoLua<'lua>> IntoLua<'lua> for Vec<T> {
942    #[inline]
943    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
944        Ok(Value::Table(lua.create_sequence_from(self)?))
945    }
946}
947
948impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Vec<T> {
949    #[inline]
950    fn from_lua(value: Value<'lua>, _lua: &'lua Lua) -> Result<Self> {
951        match value {
952            Value::Table(table) => table.sequence_values().collect(),
953            _ => Err(Error::FromLuaConversionError {
954                from: value.type_name(),
955                to: "Vec",
956                message: Some("expected table".to_string()),
957            }),
958        }
959    }
960}
961
962impl<'lua, K: Eq + Hash + IntoLua<'lua>, V: IntoLua<'lua>, S: BuildHasher> IntoLua<'lua>
963    for HashMap<K, V, S>
964{
965    #[inline]
966    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
967        Ok(Value::Table(lua.create_table_from(self)?))
968    }
969}
970
971impl<'lua, K: Eq + Hash + FromLua<'lua>, V: FromLua<'lua>, S: BuildHasher + Default> FromLua<'lua>
972    for HashMap<K, V, S>
973{
974    #[inline]
975    fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
976        if let Value::Table(table) = value {
977            table.pairs().collect()
978        } else {
979            Err(Error::FromLuaConversionError {
980                from: value.type_name(),
981                to: "HashMap",
982                message: Some("expected table".to_string()),
983            })
984        }
985    }
986}
987
988impl<'lua, K: Ord + IntoLua<'lua>, V: IntoLua<'lua>> IntoLua<'lua> for BTreeMap<K, V> {
989    #[inline]
990    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
991        Ok(Value::Table(lua.create_table_from(self)?))
992    }
993}
994
995impl<'lua, K: Ord + FromLua<'lua>, V: FromLua<'lua>> FromLua<'lua> for BTreeMap<K, V> {
996    #[inline]
997    fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
998        if let Value::Table(table) = value {
999            table.pairs().collect()
1000        } else {
1001            Err(Error::FromLuaConversionError {
1002                from: value.type_name(),
1003                to: "BTreeMap",
1004                message: Some("expected table".to_string()),
1005            })
1006        }
1007    }
1008}
1009
1010impl<'lua, T: Eq + Hash + IntoLua<'lua>, S: BuildHasher> IntoLua<'lua> for HashSet<T, S> {
1011    #[inline]
1012    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
1013        Ok(Value::Table(lua.create_table_from(
1014            self.into_iter().map(|val| (val, true)),
1015        )?))
1016    }
1017}
1018
1019impl<'lua, T: Eq + Hash + FromLua<'lua>, S: BuildHasher + Default> FromLua<'lua> for HashSet<T, S> {
1020    #[inline]
1021    fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
1022        match value {
1023            Value::Table(table) if table.raw_len() > 0 => table.sequence_values().collect(),
1024            Value::Table(table) => table
1025                .pairs::<T, Value<'lua>>()
1026                .map(|res| res.map(|(k, _)| k))
1027                .collect(),
1028            _ => Err(Error::FromLuaConversionError {
1029                from: value.type_name(),
1030                to: "HashSet",
1031                message: Some("expected table".to_string()),
1032            }),
1033        }
1034    }
1035}
1036
1037impl<'lua, T: Ord + IntoLua<'lua>> IntoLua<'lua> for BTreeSet<T> {
1038    #[inline]
1039    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
1040        Ok(Value::Table(lua.create_table_from(
1041            self.into_iter().map(|val| (val, true)),
1042        )?))
1043    }
1044}
1045
1046impl<'lua, T: Ord + FromLua<'lua>> FromLua<'lua> for BTreeSet<T> {
1047    #[inline]
1048    fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
1049        match value {
1050            Value::Table(table) if table.raw_len() > 0 => table.sequence_values().collect(),
1051            Value::Table(table) => table
1052                .pairs::<T, Value<'lua>>()
1053                .map(|res| res.map(|(k, _)| k))
1054                .collect(),
1055            _ => Err(Error::FromLuaConversionError {
1056                from: value.type_name(),
1057                to: "BTreeSet",
1058                message: Some("expected table".to_string()),
1059            }),
1060        }
1061    }
1062}
1063
1064impl<'lua, T: IntoLua<'lua>> IntoLua<'lua> for Option<T> {
1065    #[inline]
1066    fn into_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
1067        match self {
1068            Some(val) => val.into_lua(lua),
1069            None => Ok(Nil),
1070        }
1071    }
1072
1073    #[inline]
1074    unsafe fn push_into_stack(self, lua: &'lua Lua) -> Result<()> {
1075        match self {
1076            Some(val) => val.push_into_stack(lua)?,
1077            None => ffi::lua_pushnil(lua.state()),
1078        }
1079        Ok(())
1080    }
1081}
1082
1083impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Option<T> {
1084    #[inline]
1085    fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
1086        match value {
1087            Nil => Ok(None),
1088            value => Ok(Some(T::from_lua(value, lua)?)),
1089        }
1090    }
1091
1092    #[inline]
1093    unsafe fn from_stack(idx: c_int, lua: &'lua Lua) -> Result<Self> {
1094        if ffi::lua_isnil(lua.state(), idx) != 0 {
1095            Ok(None)
1096        } else {
1097            Ok(Some(T::from_stack(idx, lua)?))
1098        }
1099    }
1100}