1use crate::Lua;
9use crate::error::{LuaError, LuaResult, RuntimeError};
10use crate::handles::{AnyUserData, Function, Table, Thread};
11use crate::vm::value::Val;
12
13pub trait IntoLua {
22 fn into_lua(self, lua: &mut Lua) -> LuaResult<Val>;
24}
25
26pub trait FromLua: Sized {
30 fn from_lua(val: Val, lua: &Lua) -> LuaResult<Self>;
32}
33
34pub trait IntoLuaMulti {
40 fn into_lua_multi(self, lua: &mut Lua) -> LuaResult<Vec<Val>>;
42}
43
44pub trait FromLuaMulti: Sized {
46 fn from_lua_multi(values: &[Val], lua: &Lua) -> LuaResult<Self>;
48}
49
50impl IntoLua for Val {
55 fn into_lua(self, _lua: &mut Lua) -> LuaResult<Val> {
56 Ok(self)
57 }
58}
59
60impl FromLua for Val {
61 fn from_lua(val: Val, _lua: &Lua) -> LuaResult<Self> {
62 Ok(val)
63 }
64}
65
66impl IntoLua for () {
71 fn into_lua(self, _lua: &mut Lua) -> LuaResult<Val> {
72 Ok(Val::Nil)
73 }
74}
75
76impl FromLua for () {
77 fn from_lua(_val: Val, _lua: &Lua) -> LuaResult<Self> {
78 Ok(())
79 }
80}
81
82impl IntoLua for bool {
87 fn into_lua(self, _lua: &mut Lua) -> LuaResult<Val> {
88 Ok(Val::Bool(self))
89 }
90}
91
92impl FromLua for bool {
93 fn from_lua(val: Val, _lua: &Lua) -> LuaResult<Self> {
94 match val {
95 Val::Bool(b) => Ok(b),
96 Val::Nil => Ok(false),
97 _ => Ok(true),
98 }
99 }
100}
101
102impl IntoLua for f64 {
107 fn into_lua(self, _lua: &mut Lua) -> LuaResult<Val> {
108 Ok(Val::Num(self))
109 }
110}
111
112impl FromLua for f64 {
113 fn from_lua(val: Val, _lua: &Lua) -> LuaResult<Self> {
114 match val {
115 Val::Num(n) => Ok(n),
116 _ => Err(conversion_error("number", val.type_name())),
117 }
118 }
119}
120
121impl IntoLua for f32 {
122 fn into_lua(self, _lua: &mut Lua) -> LuaResult<Val> {
123 Ok(Val::Num(f64::from(self)))
124 }
125}
126
127impl FromLua for f32 {
128 fn from_lua(val: Val, _lua: &Lua) -> LuaResult<Self> {
129 match val {
130 Val::Num(n) => Ok(n as Self),
131 _ => Err(conversion_error("number", val.type_name())),
132 }
133 }
134}
135
136macro_rules! impl_integer_into_lua {
141 ($($ty:ty),*) => {
142 $(
143 impl IntoLua for $ty {
144 #[allow(clippy::cast_lossless, trivial_numeric_casts)]
145 fn into_lua(self, _lua: &mut Lua) -> LuaResult<Val> {
146 Ok(Val::Num(self as f64))
147 }
148 }
149 )*
150 };
151}
152
153impl_integer_into_lua!(i8, i16, i32, i64, u8, u16, u32, u64, isize, usize);
154
155macro_rules! impl_integer_from_lua {
156 ($($ty:ty),*) => {
157 $(
158 impl FromLua for $ty {
159 #[allow(clippy::cast_lossless, trivial_numeric_casts)]
160 fn from_lua(val: Val, _lua: &Lua) -> LuaResult<Self> {
161 match val {
162 Val::Num(n) => {
163 if n.fract() != 0.0 {
164 return Err(conversion_error(
165 concat!("integer (", stringify!($ty), ")"),
166 "float",
167 ));
168 }
169 let min = <$ty>::MIN as f64;
170 let max = <$ty>::MAX as f64;
171 if n < min || n > max {
172 return Err(conversion_error(
173 concat!("integer (", stringify!($ty), ")"),
174 "number out of range",
175 ));
176 }
177 Ok(n as $ty)
178 }
179 _ => Err(conversion_error(
180 concat!("integer (", stringify!($ty), ")"),
181 val.type_name(),
182 )),
183 }
184 }
185 }
186 )*
187 };
188}
189
190impl_integer_from_lua!(i8, i16, i32, i64, u8, u16, u32, u64, isize, usize);
191
192impl IntoLua for String {
197 fn into_lua(self, lua: &mut Lua) -> LuaResult<Val> {
198 let r = lua.state_mut().gc.intern_string(self.as_bytes());
199 Ok(Val::Str(r))
200 }
201}
202
203impl IntoLua for &str {
204 fn into_lua(self, lua: &mut Lua) -> LuaResult<Val> {
205 let r = lua.state_mut().gc.intern_string(self.as_bytes());
206 Ok(Val::Str(r))
207 }
208}
209
210impl IntoLua for &[u8] {
211 fn into_lua(self, lua: &mut Lua) -> LuaResult<Val> {
212 let r = lua.state_mut().gc.intern_string(self);
213 Ok(Val::Str(r))
214 }
215}
216
217impl FromLua for String {
218 fn from_lua(val: Val, lua: &Lua) -> LuaResult<Self> {
219 match val {
220 Val::Str(r) => {
221 let s = lua
222 .state()
223 .gc
224 .string_arena
225 .get(r)
226 .ok_or_else(|| conversion_error("string", "collected string"))?;
227 Ok(Self::from_utf8_lossy(s.data()).into_owned())
228 }
229 _ => Err(conversion_error("string", val.type_name())),
230 }
231 }
232}
233
234impl FromLua for Vec<u8> {
235 fn from_lua(val: Val, lua: &Lua) -> LuaResult<Self> {
236 match val {
237 Val::Str(r) => {
238 let s = lua
239 .state()
240 .gc
241 .string_arena
242 .get(r)
243 .ok_or_else(|| conversion_error("string", "collected string"))?;
244 Ok(s.data().to_vec())
245 }
246 _ => Err(conversion_error("string", val.type_name())),
247 }
248 }
249}
250
251impl<T: IntoLua> IntoLua for Option<T> {
256 fn into_lua(self, lua: &mut Lua) -> LuaResult<Val> {
257 match self {
258 Some(v) => v.into_lua(lua),
259 None => Ok(Val::Nil),
260 }
261 }
262}
263
264impl<T: FromLua> FromLua for Option<T> {
265 fn from_lua(val: Val, lua: &Lua) -> LuaResult<Self> {
266 match val {
267 Val::Nil => Ok(None),
268 other => Ok(Some(T::from_lua(other, lua)?)),
269 }
270 }
271}
272
273impl IntoLua for Table {
278 fn into_lua(self, _lua: &mut Lua) -> LuaResult<Val> {
279 Ok(Val::Table(self.gc_ref()))
280 }
281}
282
283impl FromLua for Table {
284 fn from_lua(val: Val, _lua: &Lua) -> LuaResult<Self> {
285 match val {
286 Val::Table(r) => Ok(Self(r)),
287 _ => Err(conversion_error("table", val.type_name())),
288 }
289 }
290}
291
292impl IntoLua for Function {
293 fn into_lua(self, _lua: &mut Lua) -> LuaResult<Val> {
294 Ok(Val::Function(self.gc_ref()))
295 }
296}
297
298impl FromLua for Function {
299 fn from_lua(val: Val, _lua: &Lua) -> LuaResult<Self> {
300 match val {
301 Val::Function(r) => Ok(Self(r)),
302 _ => Err(conversion_error("function", val.type_name())),
303 }
304 }
305}
306
307impl IntoLua for Thread {
308 fn into_lua(self, _lua: &mut Lua) -> LuaResult<Val> {
309 Ok(Val::Thread(self.gc_ref()))
310 }
311}
312
313impl FromLua for Thread {
314 fn from_lua(val: Val, _lua: &Lua) -> LuaResult<Self> {
315 match val {
316 Val::Thread(r) => Ok(Self(r)),
317 _ => Err(conversion_error("thread", val.type_name())),
318 }
319 }
320}
321
322impl IntoLua for AnyUserData {
323 fn into_lua(self, _lua: &mut Lua) -> LuaResult<Val> {
324 Ok(Val::Userdata(self.gc_ref()))
325 }
326}
327
328impl FromLua for AnyUserData {
329 fn from_lua(val: Val, _lua: &Lua) -> LuaResult<Self> {
330 match val {
331 Val::Userdata(r) => Ok(Self(r)),
332 _ => Err(conversion_error("userdata", val.type_name())),
333 }
334 }
335}
336
337impl IntoLuaMulti for Vec<Val> {
342 fn into_lua_multi(self, _lua: &mut Lua) -> LuaResult<Vec<Val>> {
343 Ok(self)
344 }
345}
346
347impl FromLuaMulti for Vec<Val> {
348 fn from_lua_multi(values: &[Val], _lua: &Lua) -> LuaResult<Self> {
349 Ok(values.to_vec())
350 }
351}
352
353impl IntoLuaMulti for () {
358 fn into_lua_multi(self, _lua: &mut Lua) -> LuaResult<Vec<Val>> {
359 Ok(vec![])
360 }
361}
362
363impl FromLuaMulti for () {
364 fn from_lua_multi(_values: &[Val], _lua: &Lua) -> LuaResult<Self> {
365 Ok(())
366 }
367}
368
369macro_rules! impl_tuple_multi {
374 ($($idx:tt : $T:ident),+) => {
375 impl<$($T: IntoLua),+> IntoLuaMulti for ($($T,)+) {
376 fn into_lua_multi(self, lua: &mut Lua) -> LuaResult<Vec<Val>> {
377 Ok(vec![
378 $(self.$idx.into_lua(lua)?,)+
379 ])
380 }
381 }
382
383 impl<$($T: FromLua),+> FromLuaMulti for ($($T,)+) {
384 fn from_lua_multi(values: &[Val], lua: &Lua) -> LuaResult<Self> {
385 Ok((
386 $(
387 $T::from_lua(
388 values.get($idx).copied().unwrap_or(Val::Nil),
389 lua,
390 )?,
391 )+
392 ))
393 }
394 }
395 };
396}
397
398impl_tuple_multi!(0: A);
399impl_tuple_multi!(0: A, 1: B);
400impl_tuple_multi!(0: A, 1: B, 2: C);
401impl_tuple_multi!(0: A, 1: B, 2: C, 3: D);
402impl_tuple_multi!(0: A, 1: B, 2: C, 3: D, 4: E);
403impl_tuple_multi!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F);
404impl_tuple_multi!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G);
405impl_tuple_multi!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H);
406
407fn conversion_error(expected: &str, got: &str) -> LuaError {
412 LuaError::Runtime(RuntimeError {
413 message: format!("{expected} expected, got {got}"),
414 level: 0,
415 traceback: vec![],
416 })
417}
418
419#[cfg(test)]
424mod tests {
425 use super::*;
426
427 fn make_lua() -> Lua {
428 Lua::new_empty()
429 }
430
431 #[test]
434 fn val_round_trip() {
435 let mut lua = make_lua();
436 let v = Val::Num(7.5);
437 let converted = v.into_lua(&mut lua);
438 assert!(converted.is_ok());
439 assert_eq!(converted.ok(), Some(Val::Num(7.5)));
440
441 let back = Val::from_lua(Val::Num(7.5), &lua);
442 assert!(back.is_ok());
443 assert_eq!(back.ok(), Some(Val::Num(7.5)));
444 }
445
446 #[test]
449 fn unit_to_nil() {
450 let mut lua = make_lua();
451 let v = ().into_lua(&mut lua);
452 assert_eq!(v.ok(), Some(Val::Nil));
453 }
454
455 #[test]
456 fn unit_from_anything() {
457 let lua = make_lua();
458 let v = <()>::from_lua(Val::Num(42.0), &lua);
459 assert!(v.is_ok());
460 }
461
462 #[test]
465 fn bool_round_trip() {
466 let mut lua = make_lua();
467 let v = true.into_lua(&mut lua);
468 assert_eq!(v.ok(), Some(Val::Bool(true)));
469
470 let back = bool::from_lua(Val::Bool(true), &lua);
471 assert_eq!(back.ok(), Some(true));
472 }
473
474 #[test]
475 fn bool_from_nil_is_false() {
476 let lua = make_lua();
477 let v = bool::from_lua(Val::Nil, &lua);
478 assert_eq!(v.ok(), Some(false));
479 }
480
481 #[test]
482 fn bool_from_number_is_true() {
483 let lua = make_lua();
484 let v = bool::from_lua(Val::Num(0.0), &lua);
485 assert_eq!(v.ok(), Some(true));
486 }
487
488 #[test]
491 fn f64_round_trip() {
492 let mut lua = make_lua();
493 let v = 9.75f64.into_lua(&mut lua);
494 assert_eq!(v.ok(), Some(Val::Num(9.75)));
495
496 let back = f64::from_lua(Val::Num(9.75), &lua);
497 assert_eq!(back.ok(), Some(9.75));
498 }
499
500 #[test]
501 fn f64_from_string_fails() {
502 let mut lua = make_lua();
503 let r = lua.state_mut().gc.intern_string(b"hello");
504 let v = f64::from_lua(Val::Str(r), &lua);
505 assert!(v.is_err());
506 }
507
508 #[test]
511 fn i32_round_trip() {
512 let mut lua = make_lua();
513 let v = 42i32.into_lua(&mut lua);
514 assert_eq!(v.ok(), Some(Val::Num(42.0)));
515
516 let back = i32::from_lua(Val::Num(42.0), &lua);
517 assert_eq!(back.ok(), Some(42));
518 }
519
520 #[test]
521 fn i32_from_float_fails() {
522 let lua = make_lua();
523 let v = i32::from_lua(Val::Num(5.75), &lua);
524 assert!(v.is_err());
525 }
526
527 #[test]
528 fn u8_overflow_fails() {
529 let lua = make_lua();
530 let v = u8::from_lua(Val::Num(256.0), &lua);
531 assert!(v.is_err());
532 }
533
534 #[test]
535 fn u8_negative_fails() {
536 let lua = make_lua();
537 let v = u8::from_lua(Val::Num(-1.0), &lua);
538 assert!(v.is_err());
539 }
540
541 #[test]
544 fn string_round_trip() {
545 let mut lua = make_lua();
546 let val = "hello".into_lua(&mut lua).ok().unwrap_or(Val::Nil);
547 assert!(matches!(val, Val::Str(_)));
548
549 let back = String::from_lua(val, &lua);
550 assert_eq!(back.ok(), Some("hello".to_string()));
551 }
552
553 #[test]
554 fn string_owned_round_trip() {
555 let mut lua = make_lua();
556 let v = String::from("world").into_lua(&mut lua);
557 assert!(v.is_ok());
558 }
559
560 #[test]
561 fn bytes_round_trip() {
562 let mut lua = make_lua();
563 let val = b"binary\x00data"
564 .as_slice()
565 .into_lua(&mut lua)
566 .ok()
567 .unwrap_or(Val::Nil);
568 assert!(matches!(val, Val::Str(_)));
569
570 let back = Vec::<u8>::from_lua(val, &lua);
571 assert_eq!(back.ok(), Some(b"binary\x00data".to_vec()));
572 }
573
574 #[test]
577 fn option_some() {
578 let mut lua = make_lua();
579 let v = Some(42.0f64).into_lua(&mut lua);
580 assert_eq!(v.ok(), Some(Val::Num(42.0)));
581
582 let back = Option::<f64>::from_lua(Val::Num(42.0), &lua);
583 assert_eq!(back.ok(), Some(Some(42.0)));
584 }
585
586 #[test]
587 fn option_none() {
588 let mut lua = make_lua();
589 let v = Option::<f64>::None.into_lua(&mut lua);
590 assert_eq!(v.ok(), Some(Val::Nil));
591
592 let back = Option::<f64>::from_lua(Val::Nil, &lua);
593 assert_eq!(back.ok(), Some(None));
594 }
595
596 #[test]
599 fn anyuserdata_into_from_lua() {
600 let mut lua = make_lua();
601 let ud = crate::vm::value::Userdata::new(Box::new(123i64));
602 let r = lua.state_mut().gc.alloc_userdata(ud);
603 let handle = AnyUserData(r);
604
605 let val = handle.into_lua(&mut lua).ok().unwrap_or(Val::Nil);
606 assert!(matches!(val, Val::Userdata(_)));
607
608 let back = AnyUserData::from_lua(val, &lua);
609 assert!(back.is_ok());
610 assert_eq!(back.ok().map(AnyUserData::gc_ref), Some(r));
611 }
612
613 #[test]
614 fn anyuserdata_from_wrong_type() {
615 let lua = make_lua();
616 let result = AnyUserData::from_lua(Val::Num(42.0), &lua);
617 assert!(result.is_err());
618 }
619
620 #[test]
623 fn table_handle_conversion() {
624 let mut lua = make_lua();
625 let t = lua.create_table();
626 let val = t.into_lua(&mut lua).ok().unwrap_or(Val::Nil);
627 assert!(matches!(val, Val::Table(_)));
628
629 let back = Table::from_lua(val, &lua);
630 assert!(back.is_ok());
631 assert_eq!(back.ok().map(Table::gc_ref), Some(t.gc_ref()));
632 }
633
634 #[test]
637 fn vec_val_multi_round_trip() {
638 let mut lua = make_lua();
639 let vals = vec![Val::Num(1.0), Val::Num(2.0)];
640 let multi = vals.into_lua_multi(&mut lua);
641 assert_eq!(multi.ok().map(|v| v.len()), Some(2));
642 }
643
644 #[test]
645 fn unit_multi() {
646 let mut lua = make_lua();
647 let multi = ().into_lua_multi(&mut lua);
648 assert_eq!(multi.ok().map(|v| v.len()), Some(0));
649 }
650
651 #[test]
652 fn tuple_from_multi() {
653 let lua = make_lua();
654 let vals = [Val::Num(1.0), Val::Num(2.0)];
655 let result = <(f64, f64)>::from_lua_multi(&vals, &lua);
656 assert_eq!(result.ok(), Some((1.0, 2.0)));
657 }
658
659 #[test]
660 fn tuple_from_multi_missing_values() {
661 let lua = make_lua();
662 let vals = [Val::Num(1.0)];
663 let result = <(f64, Option<f64>)>::from_lua_multi(&vals, &lua);
664 assert_eq!(result.ok(), Some((1.0, None)));
665 }
666}