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