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