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