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