1#![allow(clippy::wrong_self_convention)]
2
3use std::borrow::Cow;
4use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
5use std::convert::TryInto;
6use std::ffi::{CStr, CString};
7use std::hash::{BuildHasher, Hash};
8use std::string::String as StdString;
9
10use bstr::{BStr, BString};
11use num_traits::cast;
12
13use crate::error::{Error, Result};
14use crate::function::Function;
15use crate::lua::Lua;
16use crate::string::String;
17use crate::table::Table;
18use crate::thread::Thread;
19use crate::types::{LightUserData, MaybeSend};
20use crate::userdata::{AnyUserData, UserData};
21use crate::value::{FromLua, Nil, ToLua, Value};
22
23impl<'lua> ToLua<'lua> for Value<'lua> {
24 #[inline]
25 fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
26 Ok(self)
27 }
28}
29
30impl<'lua> FromLua<'lua> for Value<'lua> {
31 #[inline]
32 fn from_lua(lua_value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
33 Ok(lua_value)
34 }
35}
36
37impl<'lua> ToLua<'lua> for String<'lua> {
38 #[inline]
39 fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
40 Ok(Value::String(self))
41 }
42}
43
44impl<'lua> FromLua<'lua> for String<'lua> {
45 #[inline]
46 fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<String<'lua>> {
47 let ty = value.type_name();
48 lua.coerce_string(value)?
49 .ok_or_else(|| Error::FromLuaConversionError {
50 from: ty,
51 to: "String",
52 message: Some("expected string or number".to_string()),
53 })
54 }
55}
56
57impl<'lua> ToLua<'lua> for Table<'lua> {
58 #[inline]
59 fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
60 Ok(Value::Table(self))
61 }
62}
63
64impl<'lua> FromLua<'lua> for Table<'lua> {
65 #[inline]
66 fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Table<'lua>> {
67 match value {
68 Value::Table(table) => Ok(table),
69 _ => Err(Error::FromLuaConversionError {
70 from: value.type_name(),
71 to: "table",
72 message: None,
73 }),
74 }
75 }
76}
77
78impl<'lua> ToLua<'lua> for Function<'lua> {
79 #[inline]
80 fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
81 Ok(Value::Function(self))
82 }
83}
84
85impl<'lua> FromLua<'lua> for Function<'lua> {
86 #[inline]
87 fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Function<'lua>> {
88 match value {
89 Value::Function(table) => Ok(table),
90 _ => Err(Error::FromLuaConversionError {
91 from: value.type_name(),
92 to: "function",
93 message: None,
94 }),
95 }
96 }
97}
98
99impl<'lua> ToLua<'lua> for Thread<'lua> {
100 #[inline]
101 fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
102 Ok(Value::Thread(self))
103 }
104}
105
106impl<'lua> FromLua<'lua> for Thread<'lua> {
107 #[inline]
108 fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Thread<'lua>> {
109 match value {
110 Value::Thread(t) => Ok(t),
111 _ => Err(Error::FromLuaConversionError {
112 from: value.type_name(),
113 to: "thread",
114 message: None,
115 }),
116 }
117 }
118}
119
120impl<'lua> ToLua<'lua> for AnyUserData<'lua> {
121 #[inline]
122 fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
123 Ok(Value::UserData(self))
124 }
125}
126
127impl<'lua> FromLua<'lua> for AnyUserData<'lua> {
128 #[inline]
129 fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<AnyUserData<'lua>> {
130 match value {
131 Value::UserData(ud) => Ok(ud),
132 _ => Err(Error::FromLuaConversionError {
133 from: value.type_name(),
134 to: "userdata",
135 message: None,
136 }),
137 }
138 }
139}
140
141impl<'lua, T: 'static + MaybeSend + UserData> ToLua<'lua> for T {
142 #[inline]
143 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
144 Ok(Value::UserData(lua.create_userdata(self)?))
145 }
146}
147
148impl<'lua, T: 'static + UserData + Clone> FromLua<'lua> for T {
149 #[inline]
150 fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<T> {
151 match value {
152 Value::UserData(ud) => Ok(ud.borrow::<T>()?.clone()),
153 _ => Err(Error::FromLuaConversionError {
154 from: value.type_name(),
155 to: "userdata",
156 message: None,
157 }),
158 }
159 }
160}
161
162impl<'lua> ToLua<'lua> for Error {
163 #[inline]
164 fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
165 Ok(Value::Error(self))
166 }
167}
168
169impl<'lua> FromLua<'lua> for Error {
170 #[inline]
171 fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Error> {
172 match value {
173 Value::Error(err) => Ok(err),
174 val => Ok(Error::RuntimeError(
175 lua.coerce_string(val)?
176 .and_then(|s| Some(s.to_str().ok()?.to_owned()))
177 .unwrap_or_else(|| "<unprintable error>".to_owned()),
178 )),
179 }
180 }
181}
182
183impl<'lua> ToLua<'lua> for bool {
184 #[inline]
185 fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
186 Ok(Value::Boolean(self))
187 }
188}
189
190impl<'lua> FromLua<'lua> for bool {
191 #[inline]
192 fn from_lua(v: Value<'lua>, _: &'lua Lua) -> Result<Self> {
193 match v {
194 Value::Nil => Ok(false),
195 Value::Boolean(b) => Ok(b),
196 _ => Ok(true),
197 }
198 }
199}
200
201impl<'lua> ToLua<'lua> for LightUserData {
202 #[inline]
203 fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
204 Ok(Value::LightUserData(self))
205 }
206}
207
208impl<'lua> FromLua<'lua> for LightUserData {
209 #[inline]
210 fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
211 match value {
212 Value::LightUserData(ud) => Ok(ud),
213 _ => Err(Error::FromLuaConversionError {
214 from: value.type_name(),
215 to: "light userdata",
216 message: None,
217 }),
218 }
219 }
220}
221
222impl<'lua> ToLua<'lua> for StdString {
223 #[inline]
224 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
225 Ok(Value::String(lua.create_string(&self)?))
226 }
227}
228
229impl<'lua> FromLua<'lua> for StdString {
230 #[inline]
231 fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
232 let ty = value.type_name();
233 Ok(lua
234 .coerce_string(value)?
235 .ok_or_else(|| Error::FromLuaConversionError {
236 from: ty,
237 to: "String",
238 message: Some("expected string or number".to_string()),
239 })?
240 .to_str()?
241 .to_owned())
242 }
243}
244
245impl<'lua> ToLua<'lua> for &str {
246 #[inline]
247 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
248 Ok(Value::String(lua.create_string(self)?))
249 }
250}
251
252impl<'lua> ToLua<'lua> for Cow<'_, str> {
253 #[inline]
254 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
255 Ok(Value::String(lua.create_string(self.as_bytes())?))
256 }
257}
258
259impl<'lua> ToLua<'lua> for Box<str> {
260 #[inline]
261 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
262 Ok(Value::String(lua.create_string(&*self)?))
263 }
264}
265
266impl<'lua> FromLua<'lua> for Box<str> {
267 #[inline]
268 fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
269 let ty = value.type_name();
270 Ok(lua
271 .coerce_string(value)?
272 .ok_or_else(|| Error::FromLuaConversionError {
273 from: ty,
274 to: "Box<str>",
275 message: Some("expected string or number".to_string()),
276 })?
277 .to_str()?
278 .to_owned()
279 .into_boxed_str())
280 }
281}
282
283impl<'lua> ToLua<'lua> for CString {
284 #[inline]
285 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
286 Ok(Value::String(lua.create_string(self.as_bytes())?))
287 }
288}
289
290impl<'lua> FromLua<'lua> for CString {
291 #[inline]
292 fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
293 let ty = value.type_name();
294 let string = lua
295 .coerce_string(value)?
296 .ok_or_else(|| Error::FromLuaConversionError {
297 from: ty,
298 to: "CString",
299 message: Some("expected string or number".to_string()),
300 })?;
301
302 match CStr::from_bytes_with_nul(string.as_bytes_with_nul()) {
303 Ok(s) => Ok(s.into()),
304 Err(_) => Err(Error::FromLuaConversionError {
305 from: ty,
306 to: "CString",
307 message: Some("invalid C-style string".to_string()),
308 }),
309 }
310 }
311}
312
313impl<'lua> ToLua<'lua> for &CStr {
314 #[inline]
315 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
316 Ok(Value::String(lua.create_string(self.to_bytes())?))
317 }
318}
319
320impl<'lua> ToLua<'lua> for Cow<'_, CStr> {
321 #[inline]
322 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
323 Ok(Value::String(lua.create_string(self.to_bytes())?))
324 }
325}
326
327impl<'lua> ToLua<'lua> for BString {
328 #[inline]
329 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
330 Ok(Value::String(lua.create_string(&self)?))
331 }
332}
333
334impl<'lua> FromLua<'lua> for BString {
335 #[inline]
336 fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
337 let ty = value.type_name();
338 Ok(BString::from(
339 lua.coerce_string(value)?
340 .ok_or_else(|| Error::FromLuaConversionError {
341 from: ty,
342 to: "String",
343 message: Some("expected string or number".to_string()),
344 })?
345 .as_bytes()
346 .to_vec(),
347 ))
348 }
349}
350
351impl<'lua> ToLua<'lua> for &BStr {
352 #[inline]
353 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
354 Ok(Value::String(lua.create_string(self)?))
355 }
356}
357
358macro_rules! lua_convert_int {
359 ($x:ty) => {
360 impl<'lua> ToLua<'lua> for $x {
361 #[inline]
362 fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
363 cast(self)
364 .map(Value::Integer)
365 .or_else(|| cast(self).map(Value::Number))
366 .ok_or_else(|| Error::ToLuaConversionError {
368 from: stringify!($x),
369 to: "number",
370 message: Some("out of range".to_owned()),
371 })
372 }
373 }
374
375 impl<'lua> FromLua<'lua> for $x {
376 #[inline]
377 fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
378 let ty = value.type_name();
379 (match value {
380 Value::Integer(i) => cast(i),
381 Value::Number(n) => cast(n),
382 _ => {
383 if let Some(i) = lua.coerce_integer(value.clone())? {
384 cast(i)
385 } else {
386 cast(lua.coerce_number(value)?.ok_or_else(|| {
387 Error::FromLuaConversionError {
388 from: ty,
389 to: stringify!($x),
390 message: Some(
391 "expected number or string coercible to number".to_string(),
392 ),
393 }
394 })?)
395 }
396 }
397 })
398 .ok_or_else(|| Error::FromLuaConversionError {
399 from: ty,
400 to: stringify!($x),
401 message: Some("out of range".to_owned()),
402 })
403 }
404 }
405 };
406}
407
408lua_convert_int!(i8);
409lua_convert_int!(u8);
410lua_convert_int!(i16);
411lua_convert_int!(u16);
412lua_convert_int!(i32);
413lua_convert_int!(u32);
414lua_convert_int!(i64);
415lua_convert_int!(u64);
416lua_convert_int!(i128);
417lua_convert_int!(u128);
418lua_convert_int!(isize);
419lua_convert_int!(usize);
420
421macro_rules! lua_convert_float {
422 ($x:ty) => {
423 impl<'lua> ToLua<'lua> for $x {
424 #[inline]
425 fn to_lua(self, _: &'lua Lua) -> Result<Value<'lua>> {
426 cast(self)
427 .ok_or_else(|| Error::ToLuaConversionError {
428 from: stringify!($x),
429 to: "number",
430 message: Some("out of range".to_string()),
431 })
432 .map(Value::Number)
433 }
434 }
435
436 impl<'lua> FromLua<'lua> for $x {
437 #[inline]
438 fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
439 let ty = value.type_name();
440 lua.coerce_number(value)?
441 .ok_or_else(|| Error::FromLuaConversionError {
442 from: ty,
443 to: stringify!($x),
444 message: Some("expected number or string coercible to number".to_string()),
445 })
446 .and_then(|n| {
447 cast(n).ok_or_else(|| Error::FromLuaConversionError {
448 from: ty,
449 to: stringify!($x),
450 message: Some("number out of range".to_string()),
451 })
452 })
453 }
454 }
455 };
456}
457
458lua_convert_float!(f32);
459lua_convert_float!(f64);
460
461impl<'lua, T> ToLua<'lua> for &[T]
462where
463 T: Clone + ToLua<'lua>,
464{
465 #[inline]
466 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
467 Ok(Value::Table(
468 lua.create_sequence_from(self.iter().cloned())?,
469 ))
470 }
471}
472
473impl<'lua, T, const N: usize> ToLua<'lua> for [T; N]
474where
475 T: ToLua<'lua>,
476{
477 #[inline]
478 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
479 Ok(Value::Table(lua.create_sequence_from(self)?))
480 }
481}
482
483impl<'lua, T, const N: usize> FromLua<'lua> for [T; N]
484where
485 T: FromLua<'lua>,
486{
487 #[inline]
488 fn from_lua(value: Value<'lua>, _lua: &'lua Lua) -> Result<Self> {
489 match value {
490 #[cfg(feature = "luau")]
491 Value::Vector(x, y, z) if N == 3 => Ok(mlua_expect!(
492 vec![
493 T::from_lua(Value::Number(x as _), _lua)?,
494 T::from_lua(Value::Number(y as _), _lua)?,
495 T::from_lua(Value::Number(z as _), _lua)?,
496 ]
497 .try_into()
498 .map_err(|_| ()),
499 "cannot convert vector to array"
500 )),
501 Value::Table(table) => {
502 let vec = table.sequence_values().collect::<Result<Vec<_>>>()?;
503 vec.try_into()
504 .map_err(|vec: Vec<T>| Error::FromLuaConversionError {
505 from: "Table",
506 to: "Array",
507 message: Some(format!("expected table of length {}, got {}", N, vec.len())),
508 })
509 }
510 _ => Err(Error::FromLuaConversionError {
511 from: value.type_name(),
512 to: "Array",
513 message: Some("expected table".to_string()),
514 }),
515 }
516 }
517}
518
519impl<'lua, T: ToLua<'lua>> ToLua<'lua> for Box<[T]> {
520 #[inline]
521 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
522 Ok(Value::Table(lua.create_sequence_from(self.into_vec())?))
523 }
524}
525
526impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Box<[T]> {
527 #[inline]
528 fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
529 Ok(Vec::<T>::from_lua(value, lua)?.into_boxed_slice())
530 }
531}
532
533impl<'lua, T: ToLua<'lua>> ToLua<'lua> for Vec<T> {
534 #[inline]
535 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
536 Ok(Value::Table(lua.create_sequence_from(self)?))
537 }
538}
539
540impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Vec<T> {
541 #[inline]
542 fn from_lua(value: Value<'lua>, _lua: &'lua Lua) -> Result<Self> {
543 match value {
544 #[cfg(feature = "luau")]
545 Value::Vector(x, y, z) => Ok(vec![
546 T::from_lua(Value::Number(x as _), _lua)?,
547 T::from_lua(Value::Number(y as _), _lua)?,
548 T::from_lua(Value::Number(z as _), _lua)?,
549 ]),
550 Value::Table(table) => table.sequence_values().collect(),
551 _ => Err(Error::FromLuaConversionError {
552 from: value.type_name(),
553 to: "Vec",
554 message: Some("expected table".to_string()),
555 }),
556 }
557 }
558}
559
560impl<'lua, K: Eq + Hash + ToLua<'lua>, V: ToLua<'lua>, S: BuildHasher> ToLua<'lua>
561 for HashMap<K, V, S>
562{
563 #[inline]
564 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
565 Ok(Value::Table(lua.create_table_from(self)?))
566 }
567}
568
569impl<'lua, K: Eq + Hash + FromLua<'lua>, V: FromLua<'lua>, S: BuildHasher + Default> FromLua<'lua>
570 for HashMap<K, V, S>
571{
572 #[inline]
573 fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
574 if let Value::Table(table) = value {
575 table.pairs().collect()
576 } else {
577 Err(Error::FromLuaConversionError {
578 from: value.type_name(),
579 to: "HashMap",
580 message: Some("expected table".to_string()),
581 })
582 }
583 }
584}
585
586impl<'lua, K: Ord + ToLua<'lua>, V: ToLua<'lua>> ToLua<'lua> for BTreeMap<K, V> {
587 #[inline]
588 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
589 Ok(Value::Table(lua.create_table_from(self)?))
590 }
591}
592
593impl<'lua, K: Ord + FromLua<'lua>, V: FromLua<'lua>> FromLua<'lua> for BTreeMap<K, V> {
594 #[inline]
595 fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
596 if let Value::Table(table) = value {
597 table.pairs().collect()
598 } else {
599 Err(Error::FromLuaConversionError {
600 from: value.type_name(),
601 to: "BTreeMap",
602 message: Some("expected table".to_string()),
603 })
604 }
605 }
606}
607
608impl<'lua, T: Eq + Hash + ToLua<'lua>, S: BuildHasher> ToLua<'lua> for HashSet<T, S> {
609 #[inline]
610 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
611 Ok(Value::Table(lua.create_table_from(
612 self.into_iter().map(|val| (val, true)),
613 )?))
614 }
615}
616
617impl<'lua, T: Eq + Hash + FromLua<'lua>, S: BuildHasher + Default> FromLua<'lua> for HashSet<T, S> {
618 #[inline]
619 fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
620 match value {
621 Value::Table(table) if table.len()? > 0 => table.sequence_values().collect(),
622 Value::Table(table) => table
623 .pairs::<T, Value<'lua>>()
624 .map(|res| res.map(|(k, _)| k))
625 .collect(),
626 _ => Err(Error::FromLuaConversionError {
627 from: value.type_name(),
628 to: "HashSet",
629 message: Some("expected table".to_string()),
630 }),
631 }
632 }
633}
634
635impl<'lua, T: Ord + ToLua<'lua>> ToLua<'lua> for BTreeSet<T> {
636 #[inline]
637 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
638 Ok(Value::Table(lua.create_table_from(
639 self.into_iter().map(|val| (val, true)),
640 )?))
641 }
642}
643
644impl<'lua, T: Ord + FromLua<'lua>> FromLua<'lua> for BTreeSet<T> {
645 #[inline]
646 fn from_lua(value: Value<'lua>, _: &'lua Lua) -> Result<Self> {
647 match value {
648 Value::Table(table) if table.len()? > 0 => table.sequence_values().collect(),
649 Value::Table(table) => table
650 .pairs::<T, Value<'lua>>()
651 .map(|res| res.map(|(k, _)| k))
652 .collect(),
653 _ => Err(Error::FromLuaConversionError {
654 from: value.type_name(),
655 to: "BTreeSet",
656 message: Some("expected table".to_string()),
657 }),
658 }
659 }
660}
661
662impl<'lua, T: ToLua<'lua>> ToLua<'lua> for Option<T> {
663 #[inline]
664 fn to_lua(self, lua: &'lua Lua) -> Result<Value<'lua>> {
665 match self {
666 Some(val) => val.to_lua(lua),
667 None => Ok(Nil),
668 }
669 }
670}
671
672impl<'lua, T: FromLua<'lua>> FromLua<'lua> for Option<T> {
673 #[inline]
674 fn from_lua(value: Value<'lua>, lua: &'lua Lua) -> Result<Self> {
675 match value {
676 Nil => Ok(None),
677 value => Ok(Some(T::from_lua(value, lua)?)),
678 }
679 }
680}