mlua/
conversion.rs

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