1use std::any::Any;
9use std::cell::{Cell, Ref, RefCell, RefMut};
10use std::collections::HashMap;
11use std::ffi::c_void;
12use std::fmt;
13use std::hash::Hash;
14use std::ops::{Deref, DerefMut};
15use std::panic::{catch_unwind, AssertUnwindSafe};
16use std::rc::Rc;
17
18use lua_stdlib::auxlib::load_buffer;
19use lua_stdlib::init::open_libs;
20use lua_types::closure::{LuaCClosure as RawLuaCClosure, LuaClosure as RawLuaClosure, LuaLClosure};
21use lua_types::gc::GcRef;
22use lua_types::string::LuaString as RawLuaString;
23use lua_types::upval::UpVal;
24use lua_types::userdata::LuaUserData as RawLuaUserData;
25use lua_types::value::{LuaTable as RawLuaTable, LuaValue as RawLuaValue};
26use lua_vm::state::{
27 new_state, CpuClockHook, DynLibLoadHook, DynLibSymbolHook, DynLibUnloadHook, EntropyHook,
28 EnvHook, ExternalRootKey, FileLoaderHook, FileOpenHook, FileRemoveHook, FileRenameHook,
29 InputHook, LuaCallable, LuaRustFunction, LuaState, OsExecuteHook, OutputHook, PopenHook,
30 TempNameHook, UnixTimeHook,
31};
32
33pub use lua_types::{LuaError, LuaFileHandle};
34pub use lua_vm::state::{DynLibId, DynamicSymbol, OsExecuteReason, OsExecuteResult};
35
36pub type Error = LuaError;
37pub type Result<T> = std::result::Result<T, Error>;
38
39#[derive(Clone, Copy, Default)]
47pub struct HostHooks {
48 pub file_loader_hook: Option<FileLoaderHook>,
49 pub file_open_hook: Option<FileOpenHook>,
50 pub stdin_hook: Option<InputHook>,
51 pub stdout_hook: Option<OutputHook>,
52 pub stderr_hook: Option<OutputHook>,
53 pub env_hook: Option<EnvHook>,
54 pub unix_time_hook: Option<UnixTimeHook>,
55 pub cpu_clock_hook: Option<CpuClockHook>,
56 pub entropy_hook: Option<EntropyHook>,
57 pub temp_name_hook: Option<TempNameHook>,
58 pub popen_hook: Option<PopenHook>,
59 pub file_remove_hook: Option<FileRemoveHook>,
60 pub file_rename_hook: Option<FileRenameHook>,
61 pub os_execute_hook: Option<OsExecuteHook>,
62 pub dynlib_load_hook: Option<DynLibLoadHook>,
63 pub dynlib_symbol_hook: Option<DynLibSymbolHook>,
64 pub dynlib_unload_hook: Option<DynLibUnloadHook>,
65}
66
67impl HostHooks {
68 pub fn new() -> Self {
69 Self::default()
70 }
71
72 pub fn file_loader(mut self, hook: FileLoaderHook) -> Self {
73 self.file_loader_hook = Some(hook);
74 self
75 }
76
77 pub fn file_open(mut self, hook: FileOpenHook) -> Self {
78 self.file_open_hook = Some(hook);
79 self
80 }
81
82 pub fn stdin(mut self, hook: InputHook) -> Self {
83 self.stdin_hook = Some(hook);
84 self
85 }
86
87 pub fn stdout(mut self, hook: OutputHook) -> Self {
88 self.stdout_hook = Some(hook);
89 self
90 }
91
92 pub fn stderr(mut self, hook: OutputHook) -> Self {
93 self.stderr_hook = Some(hook);
94 self
95 }
96
97 pub fn env(mut self, hook: EnvHook) -> Self {
98 self.env_hook = Some(hook);
99 self
100 }
101
102 pub fn unix_time(mut self, hook: UnixTimeHook) -> Self {
103 self.unix_time_hook = Some(hook);
104 self
105 }
106
107 pub fn cpu_clock(mut self, hook: CpuClockHook) -> Self {
108 self.cpu_clock_hook = Some(hook);
109 self
110 }
111
112 pub fn entropy(mut self, hook: EntropyHook) -> Self {
113 self.entropy_hook = Some(hook);
114 self
115 }
116
117 pub fn temp_name(mut self, hook: TempNameHook) -> Self {
118 self.temp_name_hook = Some(hook);
119 self
120 }
121
122 pub fn popen(mut self, hook: PopenHook) -> Self {
123 self.popen_hook = Some(hook);
124 self
125 }
126
127 pub fn file_remove(mut self, hook: FileRemoveHook) -> Self {
128 self.file_remove_hook = Some(hook);
129 self
130 }
131
132 pub fn file_rename(mut self, hook: FileRenameHook) -> Self {
133 self.file_rename_hook = Some(hook);
134 self
135 }
136
137 pub fn os_execute(mut self, hook: OsExecuteHook) -> Self {
138 self.os_execute_hook = Some(hook);
139 self
140 }
141
142 pub fn dynlib_load(mut self, hook: DynLibLoadHook) -> Self {
143 self.dynlib_load_hook = Some(hook);
144 self
145 }
146
147 pub fn dynlib_symbol(mut self, hook: DynLibSymbolHook) -> Self {
148 self.dynlib_symbol_hook = Some(hook);
149 self
150 }
151
152 pub fn dynlib_unload(mut self, hook: DynLibUnloadHook) -> Self {
153 self.dynlib_unload_hook = Some(hook);
154 self
155 }
156
157 pub fn install(self, state: &mut LuaState) {
158 let global = &mut *state.global_mut();
159 global.file_loader_hook = self.file_loader_hook;
160 global.file_open_hook = self.file_open_hook;
161 global.stdin_hook = self.stdin_hook;
162 global.stdout_hook = self.stdout_hook;
163 global.stderr_hook = self.stderr_hook;
164 global.env_hook = self.env_hook;
165 global.unix_time_hook = self.unix_time_hook;
166 global.cpu_clock_hook = self.cpu_clock_hook;
167 global.entropy_hook = self.entropy_hook;
168 global.temp_name_hook = self.temp_name_hook;
169 global.popen_hook = self.popen_hook;
170 global.file_remove_hook = self.file_remove_hook;
171 global.file_rename_hook = self.file_rename_hook;
172 global.os_execute_hook = self.os_execute_hook;
173 global.dynlib_load_hook = self.dynlib_load_hook;
174 global.dynlib_symbol_hook = self.dynlib_symbol_hook;
175 global.dynlib_unload_hook = self.dynlib_unload_hook;
176 }
177}
178
179#[derive(Clone)]
186pub struct Lua {
187 inner: Rc<LuaInner>,
188}
189
190struct LuaInner {
191 state: RefCell<LuaState>,
192 active_state: Cell<*mut LuaState>,
193 pending_external_unroots: RefCell<Vec<ExternalRootKey>>,
194}
195
196struct UserDataCell<T> {
197 value: RefCell<T>,
198}
199
200struct RustCallbackCell {
201 function: LuaRustFunction,
202}
203
204struct ActiveStateGuard<'a> {
205 inner: &'a LuaInner,
206 previous: *mut LuaState,
207}
208
209impl Drop for ActiveStateGuard<'_> {
210 fn drop(&mut self) {
211 self.inner.active_state.set(self.previous);
212 }
213}
214
215impl LuaInner {
216 fn enter_active(&self, state: *mut LuaState) -> ActiveStateGuard<'_> {
217 let previous = self.active_state.replace(state);
218 ActiveStateGuard {
219 inner: self,
220 previous,
221 }
222 }
223
224 fn flush_pending_external_unroots(&self, state: &mut LuaState) {
225 let pending = self.pending_external_unroots.replace(Vec::new());
226 if pending.is_empty() {
227 return;
228 }
229
230 let mut still_pending = Vec::new();
231 for key in pending {
232 if state.try_external_unroot_value(key).is_err() {
233 still_pending.push(key);
234 }
235 }
236
237 if !still_pending.is_empty() {
238 self.pending_external_unroots
239 .borrow_mut()
240 .extend(still_pending);
241 }
242 }
243}
244
245impl fmt::Debug for Lua {
246 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247 f.debug_struct("Lua").finish_non_exhaustive()
248 }
249}
250
251impl Lua {
252 pub fn new() -> Self {
254 Self::try_new().expect("Lua runtime should initialize")
255 }
256
257 pub fn try_new() -> Result<Self> {
259 Self::with_hooks(HostHooks::default())
260 }
261
262 pub fn with_hooks(hooks: HostHooks) -> Result<Self> {
264 let mut state = new_state().ok_or(LuaError::Memory)?;
265 install_parser_hook(&mut state);
266 hooks.install(&mut state);
267 open_libs(&mut state)?;
268 Ok(Self::from_initialized_state(state))
269 }
270
271 fn from_initialized_state(state: LuaState) -> Self {
272 Lua {
273 inner: Rc::new(LuaInner {
274 state: RefCell::new(state),
275 active_state: Cell::new(std::ptr::null_mut()),
276 pending_external_unroots: RefCell::new(Vec::new()),
277 }),
278 }
279 }
280
281 fn with_state<R>(&self, f: impl FnOnce(&mut LuaState) -> R) -> R {
282 if let Ok(mut state) = self.inner.state.try_borrow_mut() {
283 let _active = self.inner.enter_active(&mut *state);
284 self.inner.flush_pending_external_unroots(&mut state);
285 let result = f(&mut state);
286 self.inner.flush_pending_external_unroots(&mut state);
287 return result;
288 }
289
290 let state = self
291 .active_state_mut()
292 .expect("re-entrant Lua access without an active state");
293 let result = f(state);
294 self.inner.flush_pending_external_unroots(state);
295 result
296 }
297
298 fn active_state_mut(&self) -> Option<&mut LuaState> {
299 let state = self.inner.active_state.get();
300 if state.is_null() {
301 return None;
302 }
303
304 Some(unsafe { &mut *state })
310 }
311
312 fn unroot_external_key(&self, key: ExternalRootKey) {
313 let removed = if let Ok(mut state) = self.inner.state.try_borrow_mut() {
314 let _active = self.inner.enter_active(&mut *state);
315 self.inner.flush_pending_external_unroots(&mut state);
316 let removed = state.try_external_unroot_value(key).is_ok();
317 self.inner.flush_pending_external_unroots(&mut state);
318 removed
319 } else {
320 if let Some(state) = self.active_state_mut() {
321 let removed = state.try_external_unroot_value(key).is_ok();
322 self.inner.flush_pending_external_unroots(state);
323 removed
324 } else {
325 false
326 }
327 };
328
329 if !removed {
330 self.inner.pending_external_unroots.borrow_mut().push(key);
331 }
332 }
333
334 fn root_raw(&self, value: RawLuaValue) -> RootedValue {
335 let key = self.with_state(|state| state.external_root_value(value));
336 RootedValue {
337 lua: self.clone(),
338 key,
339 }
340 }
341
342 fn root_raw_in_state(&self, state: &mut LuaState, value: RawLuaValue) -> RootedValue {
343 let key = state.external_root_value(value);
344 RootedValue {
345 lua: self.clone(),
346 key,
347 }
348 }
349
350 fn userdata_cell<'a, T: 'static>(
351 &self,
352 userdata: &'a AnyUserData,
353 ) -> Result<&'a UserDataCell<T>> {
354 if !Rc::ptr_eq(&self.inner, &userdata.root.lua.inner) {
355 return Err(LuaError::runtime(format_args!(
356 "Lua userdata belongs to a different state"
357 )));
358 }
359 userdata.host_cell()
360 }
361
362 pub fn load(&self, source: impl AsRef<[u8]>) -> Chunk {
364 Chunk {
365 lua: self.clone(),
366 source: source.as_ref().to_vec(),
367 name: b"chunk".to_vec(),
368 }
369 }
370
371 pub fn globals(&self) -> Table {
373 let raw = self.with_state(|state| state.global().globals.clone());
374 Table {
375 root: self.root_raw(raw),
376 }
377 }
378
379 pub fn create_table(&self) -> Result<Table> {
381 let root = self.with_state(|state| {
382 let _heap_guard = heap_guard(state);
383 let table = state.new_table();
384 let raw = RawLuaValue::Table(table);
385 let key = state.external_root_value(raw);
386 state.gc().check_step();
387 RootedValue {
388 lua: self.clone(),
389 key,
390 }
391 });
392 Ok(Table { root })
393 }
394
395 pub fn create_string(&self, bytes: impl AsRef<[u8]>) -> Result<LuaString> {
397 let bytes = bytes.as_ref();
398 let root = self.with_state(|state| {
399 let _heap_guard = heap_guard(state);
400 let string = state.new_string(bytes)?;
401 let raw = RawLuaValue::Str(string);
402 let key = state.external_root_value(raw);
403 state.gc().check_step();
404 Ok::<_, LuaError>(RootedValue {
405 lua: self.clone(),
406 key,
407 })
408 })?;
409 Ok(LuaString { root })
410 }
411
412 pub fn create_function<A, R, F>(&self, func: F) -> Result<Function>
413 where
414 A: FromLuaMulti + 'static,
415 R: IntoLuaMulti + 'static,
416 F: Fn(&Lua, A) -> Result<R> + 'static,
417 {
418 let lua = self.clone();
419 let callable: LuaRustFunction = Rc::new(move |state| {
420 match catch_unwind(AssertUnwindSafe(|| {
421 let args = callback_args(state, &lua)?;
422 let args = A::from_lua_multi(args, &lua)?;
423 let returns = func(&lua, args)?;
424 let returns = returns.into_lua_multi(&lua)?;
425 push_callback_returns(state, &lua, returns)
426 })) {
427 Ok(result) => result,
428 Err(_) => Err(LuaError::runtime(format_args!("Rust callback panicked"))),
429 }
430 });
431 self.create_registered_function(callable)
432 }
433
434 pub fn create_function_mut<A, R, F>(&self, func: F) -> Result<Function>
435 where
436 A: FromLuaMulti + 'static,
437 R: IntoLuaMulti + 'static,
438 F: FnMut(&Lua, A) -> Result<R> + 'static,
439 {
440 let func = RefCell::new(func);
441 self.create_function(move |lua, args| {
442 let mut func = func.try_borrow_mut().map_err(|_| {
443 LuaError::runtime(format_args!("mutable Rust callback is already borrowed"))
444 })?;
445 func(lua, args)
446 })
447 }
448
449 fn create_registered_function(&self, callable: LuaRustFunction) -> Result<Function> {
450 let root = self.with_state(|state| {
451 let trampoline = rust_callback_trampoline as lua_vm::state::LuaCFunction;
452 let idx = {
453 let mut global = state.global_mut();
454 match global.c_functions.iter().position(|existing| {
455 existing
456 .as_bare()
457 .is_some_and(|existing| std::ptr::fn_addr_eq(existing, trampoline))
458 }) {
459 Some(idx) => idx,
460 None => {
461 let idx = global.c_functions.len();
462 global.c_functions.push(LuaCallable::bare(trampoline));
463 idx
464 }
465 }
466 };
467 let raw = with_heap_guard(state, || {
468 let callback_payload = GcRef::new(RawLuaUserData {
469 data: Box::new([]),
470 uv: Vec::new(),
471 metatable: RefCell::new(None),
472 host_value: RefCell::new(Some(
473 Rc::new(RustCallbackCell { function: callable }) as Rc<dyn Any>,
474 )),
475 });
476 RawLuaValue::Function(RawLuaClosure::C(GcRef::new(RawLuaCClosure {
477 func: idx,
478 upvalues: vec![RawLuaValue::UserData(callback_payload)],
479 })))
480 });
481 let key = state.external_root_value(raw);
482 state.gc().check_step();
483 RootedValue {
484 lua: self.clone(),
485 key,
486 }
487 });
488 Ok(Function { root })
489 }
490
491 fn create_userdata_method<T, A, R, F>(&self, method: F) -> Result<Function>
492 where
493 T: UserData,
494 A: FromLuaMulti + 'static,
495 R: IntoLuaMulti + 'static,
496 F: Fn(&Lua, &T, A) -> Result<R> + 'static,
497 {
498 let lua = self.clone();
499 let callable: LuaRustFunction = Rc::new(move |state| {
500 match catch_unwind(AssertUnwindSafe(|| {
501 let (userdata, args) = callback_userdata_args(state, &lua)?;
502 let args = A::from_lua_multi(args, &lua)?;
503 let cell = lua.userdata_cell::<T>(&userdata)?;
504 let value = cell.value.try_borrow().map_err(|_| {
505 LuaError::runtime(format_args!("userdata is already mutably borrowed"))
506 })?;
507 let returns = method(&lua, &value, args)?;
508 let returns = returns.into_lua_multi(&lua)?;
509 push_callback_returns(state, &lua, returns)
510 })) {
511 Ok(result) => result,
512 Err(_) => Err(LuaError::runtime(format_args!(
513 "Rust userdata method panicked"
514 ))),
515 }
516 });
517 self.create_registered_function(callable)
518 }
519
520 fn create_userdata_method_mut<T, A, R, F>(&self, method: F) -> Result<Function>
521 where
522 T: UserData,
523 A: FromLuaMulti + 'static,
524 R: IntoLuaMulti + 'static,
525 F: Fn(&Lua, &mut T, A) -> Result<R> + 'static,
526 {
527 let lua = self.clone();
528 let callable: LuaRustFunction = Rc::new(move |state| {
529 match catch_unwind(AssertUnwindSafe(|| {
530 let (userdata, args) = callback_userdata_args(state, &lua)?;
531 let args = A::from_lua_multi(args, &lua)?;
532 let cell = lua.userdata_cell::<T>(&userdata)?;
533 let mut value = cell
534 .value
535 .try_borrow_mut()
536 .map_err(|_| LuaError::runtime(format_args!("userdata is already borrowed")))?;
537 let returns = method(&lua, &mut value, args)?;
538 let returns = returns.into_lua_multi(&lua)?;
539 push_callback_returns(state, &lua, returns)
540 })) {
541 Ok(result) => result,
542 Err(_) => Err(LuaError::runtime(format_args!(
543 "Rust userdata method panicked"
544 ))),
545 }
546 });
547 self.create_registered_function(callable)
548 }
549
550 pub fn create_userdata<T>(&self, data: T) -> Result<AnyUserData>
551 where
552 T: UserData,
553 {
554 let mut methods = UserDataMethodRegistry::<T>::new(self);
555 T::add_methods(&mut methods);
556 T::add_meta_methods(&mut methods);
557 methods.finish(data)
558 }
559
560 pub fn gc_collect(&self) {
562 self.with_state(|state| state.gc().full_collect());
563 }
564}
565
566pub struct Chunk {
567 lua: Lua,
568 source: Vec<u8>,
569 name: Vec<u8>,
570}
571
572impl Chunk {
573 pub fn set_name(mut self, name: impl AsRef<[u8]>) -> Self {
574 self.name = name.as_ref().to_vec();
575 self
576 }
577
578 pub fn exec(self) -> Result<()> {
579 self.lua
580 .with_state(|state| exec_state(state, &self.source, &self.name))
581 }
582
583 pub fn eval<T: FromLuaMulti>(self) -> Result<T> {
584 let raws = self.lua.with_state(|state| {
585 let saved_top = state.top_idx();
586 let status = load_buffer(state, &self.source, &self.name)?;
587 if status != 0 {
588 let err = state.pop();
589 state.set_top_idx(saved_top);
590 return Err(LuaError::from_value(err));
591 }
592 match lua_vm::api::pcall_k(state, 0, T::NRESULTS, 0, 0, None) {
593 Ok(_) => {
594 let nresults = if T::NRESULTS < 0 {
595 state.top_idx().0.saturating_sub(saved_top.0) as i32
596 } else {
597 T::NRESULTS
598 };
599 let mut values = Vec::with_capacity(nresults as usize);
600 for _ in 0..nresults {
601 values.push(state.pop());
602 }
603 values.reverse();
604 state.set_top_idx(saved_top);
605 Ok(values)
606 }
607 Err(err) => {
608 state.set_top_idx(saved_top);
609 Err(err)
610 }
611 }
612 })?;
613 let values = raws
614 .into_iter()
615 .map(|raw| Value::from_raw(&self.lua, raw))
616 .collect::<Result<Vec<_>>>()?;
617 T::from_lua_multi(values, &self.lua)
618 }
619}
620
621#[derive(Debug)]
622struct RootedValue {
623 lua: Lua,
624 key: ExternalRootKey,
625}
626
627impl RootedValue {
628 fn raw(&self) -> Result<RawLuaValue> {
629 self.lua
630 .with_state(|state| state.external_rooted_value(self.key))
631 .ok_or_else(stale_handle_error)
632 }
633
634 fn raw_for_lua(&self, lua: &Lua, state: &LuaState) -> Result<RawLuaValue> {
635 if !Rc::ptr_eq(&self.lua.inner, &lua.inner) {
636 return Err(LuaError::runtime(format_args!(
637 "Lua handle belongs to a different state"
638 )));
639 }
640 state
641 .external_rooted_value(self.key)
642 .ok_or_else(stale_handle_error)
643 }
644}
645
646impl Clone for RootedValue {
647 fn clone(&self) -> Self {
648 let raw = self.raw().expect("rooted Lua handle should not be stale");
649 self.lua.root_raw(raw)
650 }
651}
652
653impl Drop for RootedValue {
654 fn drop(&mut self) {
655 self.lua.unroot_external_key(self.key);
656 }
657}
658
659#[derive(Debug, Clone)]
661pub enum Value {
662 Nil,
663 Boolean(bool),
664 Integer(i64),
665 Number(f64),
666 String(LuaString),
667 Table(Table),
668 Function(Function),
669 UserData(AnyUserData),
670 LightUserData(*mut c_void),
671 Thread(Thread),
672}
673
674impl Value {
675 fn from_raw(lua: &Lua, raw: RawLuaValue) -> Result<Self> {
676 lua.with_state(|state| Self::from_raw_in_state(lua, state, raw))
677 }
678
679 fn from_raw_in_state(lua: &Lua, state: &mut LuaState, raw: RawLuaValue) -> Result<Self> {
680 Ok(match raw {
681 RawLuaValue::Nil => Value::Nil,
682 RawLuaValue::Bool(v) => Value::Boolean(v),
683 RawLuaValue::Int(v) => Value::Integer(v),
684 RawLuaValue::Float(v) => Value::Number(v),
685 RawLuaValue::Str(v) => Value::String(LuaString {
686 root: lua.root_raw_in_state(state, RawLuaValue::Str(v)),
687 }),
688 RawLuaValue::Table(v) => Value::Table(Table {
689 root: lua.root_raw_in_state(state, RawLuaValue::Table(v)),
690 }),
691 RawLuaValue::Function(v) => Value::Function(Function {
692 root: lua.root_raw_in_state(state, RawLuaValue::Function(v)),
693 }),
694 RawLuaValue::UserData(v) => {
695 let host_value = v.host_value();
696 Value::UserData(AnyUserData {
697 root: lua.root_raw_in_state(state, RawLuaValue::UserData(v)),
698 host_value,
699 })
700 }
701 RawLuaValue::LightUserData(v) => Value::LightUserData(v),
702 RawLuaValue::Thread(v) => Value::Thread(Thread {
703 root: lua.root_raw_in_state(state, RawLuaValue::Thread(v)),
704 }),
705 })
706 }
707
708 fn to_raw_for_lua(&self, lua: &Lua, state: &LuaState) -> Result<RawLuaValue> {
709 match self {
710 Value::Nil => Ok(RawLuaValue::Nil),
711 Value::Boolean(v) => Ok(RawLuaValue::Bool(*v)),
712 Value::Integer(v) => Ok(RawLuaValue::Int(*v)),
713 Value::Number(v) => Ok(RawLuaValue::Float(*v)),
714 Value::String(v) => v.root.raw_for_lua(lua, state),
715 Value::Table(v) => v.root.raw_for_lua(lua, state),
716 Value::Function(v) => v.root.raw_for_lua(lua, state),
717 Value::UserData(v) => v.root.raw_for_lua(lua, state),
718 Value::LightUserData(v) => Ok(RawLuaValue::LightUserData(*v)),
719 Value::Thread(v) => v.root.raw_for_lua(lua, state),
720 }
721 }
722}
723
724#[derive(Debug, Clone)]
725pub struct Table {
726 root: RootedValue,
727}
728
729impl Table {
730 fn raw_table(&self) -> Result<GcRef<RawLuaTable>> {
731 match self.root.raw()? {
732 RawLuaValue::Table(table) => Ok(table),
733 other => Err(type_error_raw(&other, "table")),
734 }
735 }
736
737 pub fn get<K, V>(&self, key: K) -> Result<V>
738 where
739 K: IntoLua,
740 V: FromLua,
741 {
742 let lua = self.root.lua.clone();
743 let key = key.into_lua(&lua)?;
744 let value_raw = lua.with_state(|state| {
745 let key_raw = key.to_raw_for_lua(&lua, state)?;
746 let table_raw = self.root.raw_for_lua(&lua, state)?;
747 state.table_get_with_tm(&table_raw, &key_raw)
748 })?;
749 let value = Value::from_raw(&lua, value_raw)?;
750 V::from_lua(value, &lua)
751 }
752
753 pub fn set<K, V>(&self, key: K, value: V) -> Result<()>
754 where
755 K: IntoLua,
756 V: IntoLua,
757 {
758 let lua = self.root.lua.clone();
759 let key = key.into_lua(&lua)?;
760 let value = value.into_lua(&lua)?;
761 lua.with_state(|state| {
762 let key_raw = key.to_raw_for_lua(&lua, state)?;
763 let value_raw = value.to_raw_for_lua(&lua, state)?;
764 let table_raw = self.root.raw_for_lua(&lua, state)?;
765 state.table_set_with_tm(&table_raw, key_raw, value_raw)
766 })
767 }
768
769 pub fn len(&self) -> Result<u64> {
770 Ok(self.raw_table()?.getn())
771 }
772}
773
774#[derive(Debug, Clone)]
775pub struct Function {
776 root: RootedValue,
777}
778
779impl Function {
780 pub fn call<A, R>(&self, args: A) -> Result<R>
781 where
782 A: IntoLuaMulti,
783 R: FromLuaMulti,
784 {
785 let lua = self.root.lua.clone();
786 let args = args.into_lua_multi(&lua)?;
787 let result_raws = lua.with_state(|state| {
788 let arg_raws = args
789 .iter()
790 .map(|value| value.to_raw_for_lua(&lua, state))
791 .collect::<Result<Vec<_>>>()?;
792 let function_raw = self.root.raw_for_lua(&lua, state)?;
793 let saved_top = state.top_idx();
794 state.push(function_raw);
795 for arg in &arg_raws {
796 state.push(*arg);
797 }
798 match lua_vm::api::pcall_k(state, arg_raws.len() as i32, R::NRESULTS, 0, 0, None) {
799 Ok(_) => {
800 let nresults = if R::NRESULTS < 0 {
801 state.top_idx().0.saturating_sub(saved_top.0) as i32
802 } else {
803 R::NRESULTS
804 };
805 let mut results = Vec::with_capacity(nresults as usize);
806 for _ in 0..nresults {
807 results.push(state.pop());
808 }
809 results.reverse();
810 state.set_top_idx(saved_top);
811 Ok(results)
812 }
813 Err(err) => {
814 state.set_top_idx(saved_top);
815 Err(err)
816 }
817 }
818 })?;
819 let values = result_raws
820 .into_iter()
821 .map(|raw| Value::from_raw(&lua, raw))
822 .collect::<Result<Vec<_>>>()?;
823 R::from_lua_multi(values, &lua)
824 }
825}
826
827#[derive(Debug, Clone)]
828pub struct LuaString {
829 root: RootedValue,
830}
831
832impl LuaString {
833 fn raw_string(&self) -> Result<GcRef<RawLuaString>> {
834 match self.root.raw()? {
835 RawLuaValue::Str(string) => Ok(string),
836 other => Err(type_error_raw(&other, "string")),
837 }
838 }
839
840 pub fn as_bytes(&self) -> Result<Vec<u8>> {
841 Ok(self.raw_string()?.as_bytes().to_vec())
842 }
843
844 pub fn to_str(&self) -> Result<String> {
845 let bytes = self.as_bytes()?;
846 String::from_utf8(bytes)
847 .map_err(|_| LuaError::runtime(format_args!("string is not valid UTF-8")))
848 }
849}
850
851#[derive(Clone)]
852pub struct AnyUserData {
853 root: RootedValue,
854 host_value: Option<Rc<dyn Any>>,
855}
856
857impl fmt::Debug for AnyUserData {
858 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
859 f.debug_struct("AnyUserData")
860 .field("root", &self.root)
861 .field("has_host_value", &self.host_value.is_some())
862 .finish()
863 }
864}
865
866impl AnyUserData {
867 fn host_cell<T: 'static>(&self) -> Result<&UserDataCell<T>> {
868 let host = self
869 .host_value
870 .as_deref()
871 .ok_or_else(|| LuaError::runtime(format_args!("missing Rust userdata payload")))?;
872 host.downcast_ref::<UserDataCell<T>>()
873 .ok_or_else(|| LuaError::runtime(format_args!("userdata type mismatch")))
874 }
875
876 pub fn borrow<T>(&self) -> Result<Ref<'_, T>>
877 where
878 T: 'static,
879 {
880 self.host_cell::<T>()?
881 .value
882 .try_borrow()
883 .map_err(|_| LuaError::runtime(format_args!("userdata is already mutably borrowed")))
884 }
885
886 pub fn borrow_mut<T>(&self) -> Result<RefMut<'_, T>>
887 where
888 T: 'static,
889 {
890 self.host_cell::<T>()?
891 .value
892 .try_borrow_mut()
893 .map_err(|_| LuaError::runtime(format_args!("userdata is already borrowed")))
894 }
895
896 pub fn with_borrow<T, R>(&self, f: impl FnOnce(&T) -> R) -> Result<R>
897 where
898 T: 'static,
899 {
900 let value = self.borrow::<T>()?;
901 Ok(f(&value))
902 }
903
904 pub fn with_borrow_mut<T, R>(&self, f: impl FnOnce(&mut T) -> R) -> Result<R>
905 where
906 T: 'static,
907 {
908 let mut value = self.borrow_mut::<T>()?;
909 Ok(f(&mut value))
910 }
911}
912
913#[derive(Debug, Clone)]
914pub struct Thread {
915 root: RootedValue,
916}
917
918#[derive(Debug, Clone, Default, PartialEq, Eq)]
924pub struct Variadic<T>(Vec<T>);
925
926impl<T> Variadic<T> {
927 pub const fn new() -> Self {
928 Self(Vec::new())
929 }
930
931 pub fn with_capacity(capacity: usize) -> Self {
932 Self(Vec::with_capacity(capacity))
933 }
934
935 pub fn into_vec(self) -> Vec<T> {
936 self.0
937 }
938}
939
940impl<T> Deref for Variadic<T> {
941 type Target = Vec<T>;
942
943 fn deref(&self) -> &Self::Target {
944 &self.0
945 }
946}
947
948impl<T> DerefMut for Variadic<T> {
949 fn deref_mut(&mut self) -> &mut Self::Target {
950 &mut self.0
951 }
952}
953
954impl<T> From<Vec<T>> for Variadic<T> {
955 fn from(value: Vec<T>) -> Self {
956 Self(value)
957 }
958}
959
960impl<T> From<Variadic<T>> for Vec<T> {
961 fn from(value: Variadic<T>) -> Self {
962 value.0
963 }
964}
965
966impl<T> FromIterator<T> for Variadic<T> {
967 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
968 Self(Vec::from_iter(iter))
969 }
970}
971
972impl<T> IntoIterator for Variadic<T> {
973 type Item = T;
974 type IntoIter = std::vec::IntoIter<T>;
975
976 fn into_iter(self) -> Self::IntoIter {
977 self.0.into_iter()
978 }
979}
980
981pub trait UserData: 'static {
982 fn add_methods<M: UserDataMethods<Self>>(_methods: &mut M)
983 where
984 Self: Sized,
985 {
986 }
987
988 fn add_meta_methods<M: UserDataMethods<Self>>(_methods: &mut M)
989 where
990 Self: Sized,
991 {
992 }
993}
994
995pub trait UserDataMethods<T: UserData> {
996 fn add_method<A, R, F>(&mut self, name: &str, method: F)
997 where
998 A: FromLuaMulti + 'static,
999 R: IntoLuaMulti + 'static,
1000 F: Fn(&Lua, &T, A) -> Result<R> + 'static;
1001
1002 fn add_method_mut<A, R, F>(&mut self, name: &str, method: F)
1003 where
1004 A: FromLuaMulti + 'static,
1005 R: IntoLuaMulti + 'static,
1006 F: Fn(&Lua, &mut T, A) -> Result<R> + 'static;
1007
1008 fn add_meta_method<A, R, F>(&mut self, metamethod: MetaMethod, method: F)
1009 where
1010 A: FromLuaMulti + 'static,
1011 R: IntoLuaMulti + 'static,
1012 F: Fn(&Lua, &T, A) -> Result<R> + 'static;
1013
1014 fn add_meta_method_mut<A, R, F>(&mut self, metamethod: MetaMethod, method: F)
1015 where
1016 A: FromLuaMulti + 'static,
1017 R: IntoLuaMulti + 'static,
1018 F: Fn(&Lua, &mut T, A) -> Result<R> + 'static;
1019}
1020
1021#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1022pub enum MetaMethod {
1023 Index,
1024 NewIndex,
1025 Add,
1026 Sub,
1027 Mul,
1028 Div,
1029 Mod,
1030 Pow,
1031 Unm,
1032 Len,
1033 Eq,
1034 Lt,
1035 Le,
1036 Concat,
1037 Call,
1038 ToString,
1039 Pairs,
1040}
1041
1042impl MetaMethod {
1043 fn name(self) -> &'static str {
1044 match self {
1045 MetaMethod::Index => "__index",
1046 MetaMethod::NewIndex => "__newindex",
1047 MetaMethod::Add => "__add",
1048 MetaMethod::Sub => "__sub",
1049 MetaMethod::Mul => "__mul",
1050 MetaMethod::Div => "__div",
1051 MetaMethod::Mod => "__mod",
1052 MetaMethod::Pow => "__pow",
1053 MetaMethod::Unm => "__unm",
1054 MetaMethod::Len => "__len",
1055 MetaMethod::Eq => "__eq",
1056 MetaMethod::Lt => "__lt",
1057 MetaMethod::Le => "__le",
1058 MetaMethod::Concat => "__concat",
1059 MetaMethod::Call => "__call",
1060 MetaMethod::ToString => "__tostring",
1061 MetaMethod::Pairs => "__pairs",
1062 }
1063 }
1064}
1065
1066struct UserDataMethodRegistry<'lua, T: UserData> {
1067 lua: &'lua Lua,
1068 methods: Vec<(String, Function)>,
1069 meta_methods: Vec<(MetaMethod, Function)>,
1070 error: Option<LuaError>,
1071 _marker: std::marker::PhantomData<T>,
1072}
1073
1074impl<'lua, T: UserData> UserDataMethodRegistry<'lua, T> {
1075 fn new(lua: &'lua Lua) -> Self {
1076 Self {
1077 lua,
1078 methods: Vec::new(),
1079 meta_methods: Vec::new(),
1080 error: None,
1081 _marker: std::marker::PhantomData,
1082 }
1083 }
1084
1085 fn record(&mut self, result: Result<Function>, insert: impl FnOnce(&mut Self, Function)) {
1086 if self.error.is_some() {
1087 return;
1088 }
1089 match result {
1090 Ok(function) => insert(self, function),
1091 Err(err) => self.error = Some(err),
1092 }
1093 }
1094
1095 fn finish(mut self, data: T) -> Result<AnyUserData> {
1096 if let Some(err) = self.error.take() {
1097 return Err(err);
1098 }
1099
1100 let method_table = self.lua.create_table()?;
1101 for (name, function) in &self.methods {
1102 method_table.set(name.as_str(), function)?;
1103 }
1104
1105 let metatable = self.lua.create_table()?;
1106 let mut has_index = false;
1107 for (metamethod, function) in &self.meta_methods {
1108 if *metamethod == MetaMethod::Index {
1109 has_index = true;
1110 }
1111 metatable.set(metamethod.name(), function)?;
1112 }
1113 if !has_index {
1114 metatable.set(MetaMethod::Index.name(), &method_table)?;
1115 }
1116
1117 let cell: Rc<dyn Any> = Rc::new(UserDataCell {
1118 value: RefCell::new(data),
1119 });
1120 let host_value = cell.clone();
1121 let root = self.lua.with_state(|state| {
1122 let userdata = with_heap_guard(state, || {
1123 GcRef::new(RawLuaUserData {
1124 data: Box::new([]),
1125 uv: Vec::new(),
1126 metatable: RefCell::new(None),
1127 host_value: RefCell::new(None),
1128 })
1129 });
1130 let metatable_raw = metatable.root.raw_for_lua(self.lua, state)?;
1131 let RawLuaValue::Table(metatable) = metatable_raw else {
1132 return Err(type_error_raw(&metatable_raw, "table"));
1133 };
1134 userdata.set_metatable(Some(metatable));
1135 userdata.set_host_value(Some(cell));
1136 let key = state.external_root_value(RawLuaValue::UserData(userdata));
1137 Ok::<_, LuaError>(RootedValue {
1138 lua: self.lua.clone(),
1139 key,
1140 })
1141 })?;
1142 Ok(AnyUserData {
1143 root,
1144 host_value: Some(host_value),
1145 })
1146 }
1147}
1148
1149impl<T: UserData> UserDataMethods<T> for UserDataMethodRegistry<'_, T> {
1150 fn add_method<A, R, F>(&mut self, name: &str, method: F)
1151 where
1152 A: FromLuaMulti + 'static,
1153 R: IntoLuaMulti + 'static,
1154 F: Fn(&Lua, &T, A) -> Result<R> + 'static,
1155 {
1156 let name = name.to_string();
1157 let result = self.lua.create_userdata_method(method);
1158 self.record(result, move |this, function| {
1159 this.methods.push((name, function));
1160 });
1161 }
1162
1163 fn add_method_mut<A, R, F>(&mut self, name: &str, method: F)
1164 where
1165 A: FromLuaMulti + 'static,
1166 R: IntoLuaMulti + 'static,
1167 F: Fn(&Lua, &mut T, A) -> Result<R> + 'static,
1168 {
1169 let name = name.to_string();
1170 let result = self.lua.create_userdata_method_mut(method);
1171 self.record(result, move |this, function| {
1172 this.methods.push((name, function));
1173 });
1174 }
1175
1176 fn add_meta_method<A, R, F>(&mut self, metamethod: MetaMethod, method: F)
1177 where
1178 A: FromLuaMulti + 'static,
1179 R: IntoLuaMulti + 'static,
1180 F: Fn(&Lua, &T, A) -> Result<R> + 'static,
1181 {
1182 let result = self.lua.create_userdata_method(method);
1183 self.record(result, move |this, function| {
1184 this.meta_methods.push((metamethod, function));
1185 });
1186 }
1187
1188 fn add_meta_method_mut<A, R, F>(&mut self, metamethod: MetaMethod, method: F)
1189 where
1190 A: FromLuaMulti + 'static,
1191 R: IntoLuaMulti + 'static,
1192 F: Fn(&Lua, &mut T, A) -> Result<R> + 'static,
1193 {
1194 let result = self.lua.create_userdata_method_mut(method);
1195 self.record(result, move |this, function| {
1196 this.meta_methods.push((metamethod, function));
1197 });
1198 }
1199}
1200
1201pub trait IntoLua {
1202 fn into_lua(self, lua: &Lua) -> Result<Value>;
1203}
1204
1205pub trait FromLua: Sized {
1206 fn from_lua(value: Value, lua: &Lua) -> Result<Self>;
1207}
1208
1209pub trait IntoLuaMulti {
1210 fn into_lua_multi(self, lua: &Lua) -> Result<Vec<Value>>;
1211}
1212
1213pub trait FromLuaMulti: Sized {
1214 const NRESULTS: i32;
1215
1216 fn from_lua_multi(values: Vec<Value>, lua: &Lua) -> Result<Self>;
1217}
1218
1219impl IntoLua for Value {
1220 fn into_lua(self, _lua: &Lua) -> Result<Value> {
1221 Ok(self)
1222 }
1223}
1224
1225impl IntoLua for &Value {
1226 fn into_lua(self, _lua: &Lua) -> Result<Value> {
1227 Ok(self.clone())
1228 }
1229}
1230
1231impl FromLua for Value {
1232 fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
1233 Ok(value)
1234 }
1235}
1236
1237impl IntoLua for bool {
1238 fn into_lua(self, _lua: &Lua) -> Result<Value> {
1239 Ok(Value::Boolean(self))
1240 }
1241}
1242
1243impl FromLua for bool {
1244 fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
1245 match value {
1246 Value::Boolean(v) => Ok(v),
1247 other => Err(type_error_value(&other, "boolean")),
1248 }
1249 }
1250}
1251
1252impl IntoLua for i64 {
1253 fn into_lua(self, _lua: &Lua) -> Result<Value> {
1254 Ok(Value::Integer(self))
1255 }
1256}
1257
1258impl FromLua for i64 {
1259 fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
1260 match value {
1261 Value::Integer(v) => Ok(v),
1262 Value::Number(v) if v.fract() == 0.0 && v.is_finite() => Ok(v as i64),
1263 other => Err(type_error_value(&other, "integer")),
1264 }
1265 }
1266}
1267
1268impl IntoLua for i32 {
1269 fn into_lua(self, lua: &Lua) -> Result<Value> {
1270 i64::from(self).into_lua(lua)
1271 }
1272}
1273
1274impl FromLua for i32 {
1275 fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
1276 let v = i64::from_lua(value, lua)?;
1277 i32::try_from(v).map_err(|_| LuaError::runtime(format_args!("integer out of range")))
1278 }
1279}
1280
1281impl IntoLua for usize {
1282 fn into_lua(self, lua: &Lua) -> Result<Value> {
1283 let v = i64::try_from(self)
1284 .map_err(|_| LuaError::runtime(format_args!("integer out of range")))?;
1285 v.into_lua(lua)
1286 }
1287}
1288
1289impl FromLua for usize {
1290 fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
1291 let v = i64::from_lua(value, lua)?;
1292 usize::try_from(v).map_err(|_| LuaError::runtime(format_args!("integer out of range")))
1293 }
1294}
1295
1296impl IntoLua for u64 {
1297 fn into_lua(self, lua: &Lua) -> Result<Value> {
1298 let v = i64::try_from(self)
1299 .map_err(|_| LuaError::runtime(format_args!("integer out of range")))?;
1300 v.into_lua(lua)
1301 }
1302}
1303
1304impl FromLua for u64 {
1305 fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
1306 let v = i64::from_lua(value, lua)?;
1307 u64::try_from(v).map_err(|_| LuaError::runtime(format_args!("integer out of range")))
1308 }
1309}
1310
1311impl IntoLua for u32 {
1312 fn into_lua(self, lua: &Lua) -> Result<Value> {
1313 u64::from(self).into_lua(lua)
1314 }
1315}
1316
1317impl FromLua for u32 {
1318 fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
1319 let v = u64::from_lua(value, lua)?;
1320 u32::try_from(v).map_err(|_| LuaError::runtime(format_args!("integer out of range")))
1321 }
1322}
1323
1324impl IntoLua for f64 {
1325 fn into_lua(self, _lua: &Lua) -> Result<Value> {
1326 Ok(Value::Number(self))
1327 }
1328}
1329
1330impl FromLua for f64 {
1331 fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
1332 match value {
1333 Value::Integer(v) => Ok(v as f64),
1334 Value::Number(v) => Ok(v),
1335 other => Err(type_error_value(&other, "number")),
1336 }
1337 }
1338}
1339
1340impl IntoLua for &str {
1341 fn into_lua(self, lua: &Lua) -> Result<Value> {
1342 Ok(Value::String(lua.create_string(self.as_bytes())?))
1343 }
1344}
1345
1346impl IntoLua for String {
1347 fn into_lua(self, lua: &Lua) -> Result<Value> {
1348 Ok(Value::String(lua.create_string(self.into_bytes())?))
1349 }
1350}
1351
1352impl FromLua for String {
1353 fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
1354 match value {
1355 Value::String(s) => s.to_str(),
1356 other => Err(type_error_value(&other, "string")),
1357 }
1358 }
1359}
1360
1361impl IntoLua for &[u8] {
1362 fn into_lua(self, lua: &Lua) -> Result<Value> {
1363 Ok(Value::String(lua.create_string(self)?))
1364 }
1365}
1366
1367impl IntoLua for LuaString {
1368 fn into_lua(self, _lua: &Lua) -> Result<Value> {
1369 Ok(Value::String(self))
1370 }
1371}
1372
1373impl IntoLua for &LuaString {
1374 fn into_lua(self, _lua: &Lua) -> Result<Value> {
1375 Ok(Value::String(self.clone()))
1376 }
1377}
1378
1379impl FromLua for LuaString {
1380 fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
1381 match value {
1382 Value::String(v) => Ok(v),
1383 other => Err(type_error_value(&other, "string")),
1384 }
1385 }
1386}
1387
1388impl IntoLua for Table {
1389 fn into_lua(self, _lua: &Lua) -> Result<Value> {
1390 Ok(Value::Table(self))
1391 }
1392}
1393
1394impl IntoLua for &Table {
1395 fn into_lua(self, _lua: &Lua) -> Result<Value> {
1396 Ok(Value::Table(self.clone()))
1397 }
1398}
1399
1400impl FromLua for Table {
1401 fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
1402 match value {
1403 Value::Table(v) => Ok(v),
1404 other => Err(type_error_value(&other, "table")),
1405 }
1406 }
1407}
1408
1409impl IntoLua for Function {
1410 fn into_lua(self, _lua: &Lua) -> Result<Value> {
1411 Ok(Value::Function(self))
1412 }
1413}
1414
1415impl IntoLua for &Function {
1416 fn into_lua(self, _lua: &Lua) -> Result<Value> {
1417 Ok(Value::Function(self.clone()))
1418 }
1419}
1420
1421impl FromLua for Function {
1422 fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
1423 match value {
1424 Value::Function(v) => Ok(v),
1425 other => Err(type_error_value(&other, "function")),
1426 }
1427 }
1428}
1429
1430impl IntoLua for AnyUserData {
1431 fn into_lua(self, _lua: &Lua) -> Result<Value> {
1432 Ok(Value::UserData(self))
1433 }
1434}
1435
1436impl IntoLua for &AnyUserData {
1437 fn into_lua(self, _lua: &Lua) -> Result<Value> {
1438 Ok(Value::UserData(self.clone()))
1439 }
1440}
1441
1442impl FromLua for AnyUserData {
1443 fn from_lua(value: Value, _lua: &Lua) -> Result<Self> {
1444 match value {
1445 Value::UserData(v) => Ok(v),
1446 other => Err(type_error_value(&other, "userdata")),
1447 }
1448 }
1449}
1450
1451impl<T> IntoLua for T
1452where
1453 T: UserData,
1454{
1455 fn into_lua(self, lua: &Lua) -> Result<Value> {
1456 Ok(Value::UserData(lua.create_userdata(self)?))
1457 }
1458}
1459
1460impl<T> IntoLua for Option<T>
1461where
1462 T: IntoLua,
1463{
1464 fn into_lua(self, lua: &Lua) -> Result<Value> {
1465 match self {
1466 Some(value) => value.into_lua(lua),
1467 None => Ok(Value::Nil),
1468 }
1469 }
1470}
1471
1472impl<T> FromLua for Option<T>
1473where
1474 T: FromLua,
1475{
1476 fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
1477 match value {
1478 Value::Nil => Ok(None),
1479 other => T::from_lua(other, lua).map(Some),
1480 }
1481 }
1482}
1483
1484impl<T> IntoLua for Vec<T>
1485where
1486 T: IntoLua,
1487{
1488 fn into_lua(self, lua: &Lua) -> Result<Value> {
1489 let table = lua.create_table()?;
1490 for (idx, value) in self.into_iter().enumerate() {
1491 table.set((idx + 1) as i64, value)?;
1492 }
1493 Ok(Value::Table(table))
1494 }
1495}
1496
1497impl<T> FromLua for Vec<T>
1498where
1499 T: FromLua,
1500{
1501 fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
1502 let table = Table::from_lua(value, lua)?;
1503 let raw = table.raw_table()?;
1504 let len = raw.getn();
1505 let mut out = Vec::with_capacity(len as usize);
1506 for idx in 1..=len {
1507 let value = Value::from_raw(lua, raw.get_int(idx as i64))?;
1508 out.push(T::from_lua(value, lua)?);
1509 }
1510 Ok(out)
1511 }
1512}
1513
1514impl<K, V> IntoLua for HashMap<K, V>
1515where
1516 K: IntoLua,
1517 V: IntoLua,
1518{
1519 fn into_lua(self, lua: &Lua) -> Result<Value> {
1520 let table = lua.create_table()?;
1521 for (key, value) in self {
1522 table.set(key, value)?;
1523 }
1524 Ok(Value::Table(table))
1525 }
1526}
1527
1528impl<K, V> FromLua for HashMap<K, V>
1529where
1530 K: FromLua + Eq + Hash,
1531 V: FromLua,
1532{
1533 fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
1534 let table = Table::from_lua(value, lua)?;
1535 let raw = table.raw_table()?;
1536 let mut out = HashMap::new();
1537 let mut result = Ok(());
1538 raw.for_each_entry(|key, value| {
1539 if result.is_err() {
1540 return;
1541 }
1542 result = (|| {
1543 let key = Value::from_raw(lua, *key)?;
1544 let value = Value::from_raw(lua, *value)?;
1545 out.insert(K::from_lua(key, lua)?, V::from_lua(value, lua)?);
1546 Ok(())
1547 })();
1548 });
1549 result?;
1550 Ok(out)
1551 }
1552}
1553
1554impl<T> IntoLuaMulti for Variadic<T>
1555where
1556 T: IntoLua,
1557{
1558 fn into_lua_multi(self, lua: &Lua) -> Result<Vec<Value>> {
1559 self.into_iter().map(|value| value.into_lua(lua)).collect()
1560 }
1561}
1562
1563impl<T> FromLuaMulti for Variadic<T>
1564where
1565 T: FromLua,
1566{
1567 const NRESULTS: i32 = -1;
1568
1569 fn from_lua_multi(values: Vec<Value>, lua: &Lua) -> Result<Self> {
1570 values
1571 .into_iter()
1572 .map(|value| T::from_lua(value, lua))
1573 .collect()
1574 }
1575}
1576
1577impl IntoLuaMulti for () {
1578 fn into_lua_multi(self, _lua: &Lua) -> Result<Vec<Value>> {
1579 Ok(Vec::new())
1580 }
1581}
1582
1583impl<T> IntoLuaMulti for T
1584where
1585 T: IntoLua,
1586{
1587 fn into_lua_multi(self, lua: &Lua) -> Result<Vec<Value>> {
1588 Ok(vec![self.into_lua(lua)?])
1589 }
1590}
1591
1592impl<A, B> IntoLuaMulti for (A, B)
1593where
1594 A: IntoLua,
1595 B: IntoLua,
1596{
1597 fn into_lua_multi(self, lua: &Lua) -> Result<Vec<Value>> {
1598 Ok(vec![self.0.into_lua(lua)?, self.1.into_lua(lua)?])
1599 }
1600}
1601
1602impl<A, T> IntoLuaMulti for (A, Variadic<T>)
1603where
1604 A: IntoLua,
1605 T: IntoLua,
1606{
1607 fn into_lua_multi(self, lua: &Lua) -> Result<Vec<Value>> {
1608 let mut values = vec![self.0.into_lua(lua)?];
1609 values.extend(self.1.into_lua_multi(lua)?);
1610 Ok(values)
1611 }
1612}
1613
1614impl<A, B, C> IntoLuaMulti for (A, B, C)
1615where
1616 A: IntoLua,
1617 B: IntoLua,
1618 C: IntoLua,
1619{
1620 fn into_lua_multi(self, lua: &Lua) -> Result<Vec<Value>> {
1621 Ok(vec![
1622 self.0.into_lua(lua)?,
1623 self.1.into_lua(lua)?,
1624 self.2.into_lua(lua)?,
1625 ])
1626 }
1627}
1628
1629impl<A, B, T> IntoLuaMulti for (A, B, Variadic<T>)
1630where
1631 A: IntoLua,
1632 B: IntoLua,
1633 T: IntoLua,
1634{
1635 fn into_lua_multi(self, lua: &Lua) -> Result<Vec<Value>> {
1636 let mut values = vec![self.0.into_lua(lua)?, self.1.into_lua(lua)?];
1637 values.extend(self.2.into_lua_multi(lua)?);
1638 Ok(values)
1639 }
1640}
1641
1642impl FromLuaMulti for () {
1643 const NRESULTS: i32 = 0;
1644
1645 fn from_lua_multi(_values: Vec<Value>, _lua: &Lua) -> Result<Self> {
1646 Ok(())
1647 }
1648}
1649
1650impl<T> FromLuaMulti for T
1651where
1652 T: FromLua,
1653{
1654 const NRESULTS: i32 = 1;
1655
1656 fn from_lua_multi(mut values: Vec<Value>, lua: &Lua) -> Result<Self> {
1657 let value = if values.is_empty() {
1658 Value::Nil
1659 } else {
1660 values.remove(0)
1661 };
1662 T::from_lua(value, lua)
1663 }
1664}
1665
1666impl<A, B> FromLuaMulti for (A, B)
1667where
1668 A: FromLua,
1669 B: FromLua,
1670{
1671 const NRESULTS: i32 = 2;
1672
1673 fn from_lua_multi(mut values: Vec<Value>, lua: &Lua) -> Result<Self> {
1674 let first = if values.is_empty() {
1675 Value::Nil
1676 } else {
1677 values.remove(0)
1678 };
1679 let second = if values.is_empty() {
1680 Value::Nil
1681 } else {
1682 values.remove(0)
1683 };
1684 Ok((A::from_lua(first, lua)?, B::from_lua(second, lua)?))
1685 }
1686}
1687
1688impl<A, T> FromLuaMulti for (A, Variadic<T>)
1689where
1690 A: FromLua,
1691 T: FromLua,
1692{
1693 const NRESULTS: i32 = -1;
1694
1695 fn from_lua_multi(mut values: Vec<Value>, lua: &Lua) -> Result<Self> {
1696 let first = if values.is_empty() {
1697 Value::Nil
1698 } else {
1699 values.remove(0)
1700 };
1701 Ok((
1702 A::from_lua(first, lua)?,
1703 Variadic::from_lua_multi(values, lua)?,
1704 ))
1705 }
1706}
1707
1708impl<A, B, C> FromLuaMulti for (A, B, C)
1709where
1710 A: FromLua,
1711 B: FromLua,
1712 C: FromLua,
1713{
1714 const NRESULTS: i32 = 3;
1715
1716 fn from_lua_multi(mut values: Vec<Value>, lua: &Lua) -> Result<Self> {
1717 let first = if values.is_empty() {
1718 Value::Nil
1719 } else {
1720 values.remove(0)
1721 };
1722 let second = if values.is_empty() {
1723 Value::Nil
1724 } else {
1725 values.remove(0)
1726 };
1727 let third = if values.is_empty() {
1728 Value::Nil
1729 } else {
1730 values.remove(0)
1731 };
1732 Ok((
1733 A::from_lua(first, lua)?,
1734 B::from_lua(second, lua)?,
1735 C::from_lua(third, lua)?,
1736 ))
1737 }
1738}
1739
1740impl<A, B, T> FromLuaMulti for (A, B, Variadic<T>)
1741where
1742 A: FromLua,
1743 B: FromLua,
1744 T: FromLua,
1745{
1746 const NRESULTS: i32 = -1;
1747
1748 fn from_lua_multi(mut values: Vec<Value>, lua: &Lua) -> Result<Self> {
1749 let first = if values.is_empty() {
1750 Value::Nil
1751 } else {
1752 values.remove(0)
1753 };
1754 let second = if values.is_empty() {
1755 Value::Nil
1756 } else {
1757 values.remove(0)
1758 };
1759 Ok((
1760 A::from_lua(first, lua)?,
1761 B::from_lua(second, lua)?,
1762 Variadic::from_lua_multi(values, lua)?,
1763 ))
1764 }
1765}
1766
1767fn rust_callback_trampoline(state: &mut LuaState) -> Result<usize> {
1768 let func_idx = state.current_call_info().func;
1769 let callback = match state.get_at(func_idx) {
1770 RawLuaValue::Function(RawLuaClosure::C(closure)) => {
1771 let Some(RawLuaValue::UserData(userdata)) = closure.upvalues.first() else {
1772 return Err(LuaError::runtime(format_args!(
1773 "missing Rust callback payload"
1774 )));
1775 };
1776 let host = userdata
1777 .host_value()
1778 .ok_or_else(|| LuaError::runtime(format_args!("missing Rust callback payload")))?;
1779 host.downcast::<RustCallbackCell>().map_err(|_| {
1780 LuaError::runtime(format_args!("Rust callback payload type mismatch"))
1781 })?
1782 }
1783 _ => {
1784 return Err(LuaError::runtime(format_args!(
1785 "Rust callback trampoline called without C closure"
1786 )));
1787 }
1788 };
1789 (callback.function)(state)
1790}
1791
1792fn with_heap_guard<R>(state: &LuaState, f: impl FnOnce() -> R) -> R {
1793 let _heap_guard = heap_guard(state);
1794 f()
1795}
1796
1797fn heap_guard(state: &LuaState) -> lua_gc::HeapGuard {
1798 let global = state.global();
1799 lua_gc::HeapGuard::push(&global.heap)
1800}
1801
1802fn callback_args(state: &mut LuaState, lua: &Lua) -> Result<Vec<Value>> {
1803 let func_idx = state.current_call_info().func;
1804 let nargs = state.top_idx().0.saturating_sub(func_idx.0 + 1);
1805 let mut args = Vec::with_capacity(nargs as usize);
1806 for i in 0..nargs {
1807 let raw = state.get_at(func_idx + 1 + i as i32);
1808 args.push(Value::from_raw_in_state(lua, state, raw)?);
1809 }
1810 Ok(args)
1811}
1812
1813fn callback_userdata_args(state: &mut LuaState, lua: &Lua) -> Result<(AnyUserData, Vec<Value>)> {
1814 let mut args = callback_args(state, lua)?;
1815 if args.is_empty() {
1816 return Err(LuaError::runtime(format_args!(
1817 "userdata method missing self argument"
1818 )));
1819 }
1820 let userdata = AnyUserData::from_lua(args.remove(0), lua)?;
1821 Ok((userdata, args))
1822}
1823
1824fn push_callback_returns(state: &mut LuaState, lua: &Lua, returns: Vec<Value>) -> Result<usize> {
1825 let mut count = 0usize;
1826 for value in returns {
1827 let raw = value.to_raw_for_lua(lua, state)?;
1828 state.push(raw);
1829 count += 1;
1830 }
1831 Ok(count)
1832}
1833
1834fn stale_handle_error() -> LuaError {
1835 LuaError::runtime(format_args!("stale Lua handle"))
1836}
1837
1838fn type_error_raw(value: &RawLuaValue, expected: &str) -> LuaError {
1839 LuaError::runtime(format_args!(
1840 "{} expected, got {}",
1841 expected,
1842 value.type_name()
1843 ))
1844}
1845
1846fn type_error_value(value: &Value, expected: &str) -> LuaError {
1847 let got = match value {
1848 Value::Nil => "nil",
1849 Value::Boolean(_) => "boolean",
1850 Value::Integer(_) | Value::Number(_) => "number",
1851 Value::String(_) => "string",
1852 Value::Table(_) => "table",
1853 Value::Function(_) => "function",
1854 Value::UserData(_) | Value::LightUserData(_) => "userdata",
1855 Value::Thread(_) => "thread",
1856 };
1857 LuaError::runtime(format_args!("{} expected, got {}", expected, got))
1858}
1859
1860pub struct LuaRuntime {
1862 state: LuaState,
1863}
1864
1865impl LuaRuntime {
1866 pub fn new() -> Result<Self> {
1872 Self::with_hooks(HostHooks::default())
1873 }
1874
1875 pub fn with_hooks(hooks: HostHooks) -> Result<Self> {
1877 let mut state = new_state().ok_or(LuaError::Memory)?;
1878 install_parser_hook(&mut state);
1879 hooks.install(&mut state);
1880 open_libs(&mut state)?;
1881 Ok(Self { state })
1882 }
1883
1884 pub fn state(&self) -> &LuaState {
1885 &self.state
1886 }
1887
1888 pub fn state_mut(&mut self) -> &mut LuaState {
1889 &mut self.state
1890 }
1891
1892 pub fn into_state(self) -> LuaState {
1893 self.state
1894 }
1895
1896 pub fn into_lua(self) -> Lua {
1897 Lua::from_initialized_state(self.state)
1898 }
1899
1900 pub fn exec(&mut self, source: &[u8], name: &[u8]) -> Result<()> {
1902 exec_state(&mut self.state, source, name)
1903 }
1904}
1905
1906fn exec_state(state: &mut LuaState, source: &[u8], name: &[u8]) -> Result<()> {
1907 let status = load_buffer(state, source, name)?;
1908 if status != 0 {
1909 let err = state.pop();
1910 return Err(LuaError::from_value(err));
1911 }
1912 lua_vm::api::pcall_k(state, 0, 0, 0, 0, None)?;
1913 Ok(())
1914}
1915
1916pub fn install_parser_hook(state: &mut LuaState) {
1917 state.global_mut().parser_hook = Some(parser_hook);
1918}
1919
1920fn parser_hook(
1921 state: &mut LuaState,
1922 source: &[u8],
1923 name: &[u8],
1924 firstchar: i32,
1925) -> Result<GcRef<LuaLClosure>> {
1926 let _heap_guard = heap_guard(state);
1927 let proto = lua_parse::parse(
1928 state,
1929 lua_parse::DynData::default(),
1930 source,
1931 name,
1932 firstchar,
1933 )?;
1934 let nupvals = proto.upvalues.len();
1935 let mut upvals = Vec::with_capacity(nupvals);
1936 for _ in 0..nupvals {
1937 upvals.push(std::cell::Cell::new(GcRef::new(UpVal::closed(
1938 RawLuaValue::Nil,
1939 ))));
1940 }
1941 Ok(GcRef::new(LuaLClosure {
1942 proto: GcRef::new(*proto),
1943 upvals,
1944 }))
1945}
1946
1947#[cfg(test)]
1948mod tests {
1949 use super::*;
1950 use std::cell::Cell;
1951
1952 fn external_root_count(lua: &Lua) -> usize {
1953 lua.with_state(|state| state.global().external_roots.len())
1954 }
1955
1956 struct Counter {
1957 value: i64,
1958 }
1959
1960 impl UserData for Counter {
1961 fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
1962 methods.add_method("get", |_lua, this, ()| Ok(this.value));
1963 methods.add_method_mut("inc", |_lua, this, delta: i64| {
1964 this.value += delta;
1965 Ok(this.value)
1966 });
1967 }
1968 }
1969
1970 struct PropertyBag {
1971 value: i64,
1972 }
1973
1974 impl UserData for PropertyBag {
1975 fn add_meta_methods<M: UserDataMethods<Self>>(methods: &mut M) {
1976 methods.add_meta_method(MetaMethod::Index, |_lua, this, key: String| {
1977 if key == "value" {
1978 Ok(Value::Integer(this.value))
1979 } else {
1980 Ok(Value::Nil)
1981 }
1982 });
1983 methods.add_meta_method_mut(
1984 MetaMethod::NewIndex,
1985 |_lua, this, (key, value): (String, i64)| {
1986 if key != "value" {
1987 return Err(LuaError::runtime(format_args!("unknown property")));
1988 }
1989 this.value = value;
1990 Ok(())
1991 },
1992 );
1993 }
1994 }
1995
1996 #[test]
1997 fn rooted_table_clone_and_drop_manage_root_slots() {
1998 let lua = Lua::new();
1999 assert_eq!(external_root_count(&lua), 0);
2000
2001 let table = lua.create_table().expect("table should allocate");
2002 assert_eq!(external_root_count(&lua), 1);
2003
2004 let cloned = table.clone();
2005 assert_eq!(external_root_count(&lua), 2);
2006
2007 drop(table);
2008 assert_eq!(external_root_count(&lua), 1);
2009
2010 cloned.set("answer", 42_i64).expect("set should succeed");
2011 lua.gc_collect();
2012 assert_eq!(
2013 cloned.get::<_, i64>("answer").expect("get should succeed"),
2014 42
2015 );
2016
2017 drop(cloned);
2018 assert_eq!(external_root_count(&lua), 0);
2019 }
2020
2021 #[test]
2022 fn table_values_survive_forced_collection_between_operations() {
2023 let lua = Lua::new();
2024 let table = lua.create_table().expect("table should allocate");
2025
2026 lua.gc_collect();
2027 table.set("k", "v").expect("set should succeed");
2028 table.set(1_i64, "array").expect("array set should succeed");
2029 lua.gc_collect();
2030
2031 let value: String = table.get("k").expect("get should succeed");
2032 assert_eq!(value, "v");
2033 assert_eq!(table.len().expect("len should succeed"), 1);
2034 }
2035
2036 #[test]
2037 fn chunk_exec_eval_and_function_call_use_rooted_handles() {
2038 let lua = Lua::new();
2039 lua.load("function add(a, b) return a + b end")
2040 .set_name("test")
2041 .exec()
2042 .expect("chunk should execute");
2043
2044 let globals = lua.globals();
2045 let add: Function = globals.get("add").expect("function should exist");
2046 let result: i64 = add.call((20_i64, 22_i64)).expect("call should work");
2047 assert_eq!(result, 42);
2048
2049 let eval_result: i64 = lua
2050 .load("return add(1, 2)")
2051 .eval()
2052 .expect("eval should work");
2053 assert_eq!(eval_result, 3);
2054 }
2055
2056 #[test]
2057 fn rust_callback_captures_state_and_reenters_lua() {
2058 let lua = Lua::new();
2059 lua.load("function twice(v) return v * 2 end")
2060 .exec()
2061 .expect("chunk should execute");
2062
2063 let globals = lua.globals();
2064 let twice: Function = globals.get("twice").expect("function should exist");
2065 let calls = Rc::new(Cell::new(0));
2066 let calls_for_callback = calls.clone();
2067
2068 let callback = lua
2069 .create_function(move |_lua, value: i64| {
2070 calls_for_callback.set(calls_for_callback.get() + 1);
2071 let doubled: i64 = twice.call(value)?;
2072 Ok(doubled + 1)
2073 })
2074 .expect("callback should create");
2075 globals
2076 .set("from_rust", callback)
2077 .expect("callback should register");
2078
2079 let result: i64 = lua
2080 .load("return from_rust(20)")
2081 .eval()
2082 .expect("callback should run");
2083 assert_eq!(result, 41);
2084 assert_eq!(calls.get(), 1);
2085 }
2086
2087 #[test]
2088 fn rust_callback_accepts_and_returns_collectable_values() {
2089 let lua = Lua::new();
2090 let globals = lua.globals();
2091 let callback = lua
2092 .create_function(|lua, name: String| {
2093 let table = lua.create_table()?;
2094 table.set("name", name)?;
2095 Ok(table)
2096 })
2097 .expect("callback should create");
2098 globals
2099 .set("make_record", callback)
2100 .expect("callback should register");
2101
2102 let result: String = lua
2103 .load("return make_record('lua-rs').name")
2104 .eval()
2105 .expect("callback should return table");
2106 assert_eq!(result, "lua-rs");
2107 }
2108
2109 #[test]
2110 fn rust_callback_mut_tracks_state() {
2111 let lua = Lua::new();
2112 let globals = lua.globals();
2113 let mut next = 0_i64;
2114 let callback = lua
2115 .create_function_mut(move |_lua, delta: i64| {
2116 next += delta;
2117 Ok(next)
2118 })
2119 .expect("callback should create");
2120 globals
2121 .set("next", callback)
2122 .expect("callback should register");
2123
2124 let result: (i64, i64) = lua
2125 .load("return next(2), next(5)")
2126 .eval()
2127 .expect("callback should run");
2128 assert_eq!(result, (2, 7));
2129 }
2130
2131 #[test]
2132 fn dropped_rust_callback_releases_captured_handles_after_gc() {
2133 let lua = Lua::new();
2134 let table = lua.create_table().expect("table should allocate");
2135 table.set("value", 42_i64).expect("set should succeed");
2136 assert_eq!(external_root_count(&lua), 1);
2137
2138 let callback = {
2139 let captured = table.clone();
2140 lua.create_function(move |_lua, ()| captured.get::<_, i64>("value"))
2141 .expect("callback should create")
2142 };
2143 assert_eq!(external_root_count(&lua), 3);
2144
2145 drop(callback);
2146 lua.gc_collect();
2147 assert_eq!(external_root_count(&lua), 1);
2148 assert_eq!(table.get::<_, i64>("value").expect("table should live"), 42);
2149 }
2150
2151 #[test]
2152 fn userdata_methods_dispatch_and_track_borrows() {
2153 let lua = Lua::new();
2154 let globals = lua.globals();
2155 let counter = lua
2156 .create_userdata(Counter { value: 1 })
2157 .expect("userdata should create");
2158 globals
2159 .set("counter", &counter)
2160 .expect("userdata should register");
2161
2162 let result: i64 = lua
2163 .load("counter:inc(5); return counter:get()")
2164 .eval()
2165 .expect("methods should dispatch");
2166 assert_eq!(result, 6);
2167 assert_eq!(
2168 counter
2169 .with_borrow::<Counter, _>(|counter| counter.value)
2170 .expect("borrow should work"),
2171 6
2172 );
2173
2174 {
2175 let borrowed = counter
2176 .borrow::<Counter>()
2177 .expect("borrow guard should work");
2178 assert_eq!(borrowed.value, 6);
2179 }
2180
2181 {
2182 let mut borrowed = counter
2183 .borrow_mut::<Counter>()
2184 .expect("mutable borrow guard should work");
2185 borrowed.value = 9;
2186 }
2187
2188 assert_eq!(
2189 lua.load("return counter:get()")
2190 .eval::<i64>()
2191 .expect("method should see guard mutation"),
2192 9
2193 );
2194 }
2195
2196 #[test]
2197 fn userdata_payload_survives_gc_while_lua_holds_userdata() {
2198 let lua = Lua::new();
2199 let globals = lua.globals();
2200 let counter = lua
2201 .create_userdata(Counter { value: 10 })
2202 .expect("userdata should create");
2203 globals
2204 .set("counter", counter)
2205 .expect("userdata should register");
2206
2207 lua.gc_collect();
2208 let result: i64 = lua
2209 .load("counter:inc(2); collectgarbage('collect'); return counter:get()")
2210 .eval()
2211 .expect("userdata should survive collection");
2212 assert_eq!(result, 12);
2213 }
2214
2215 #[test]
2216 fn userdata_runtime_borrow_conflict_returns_lua_error() {
2217 let lua = Lua::new();
2218 let globals = lua.globals();
2219 let counter = lua
2220 .create_userdata(Counter { value: 1 })
2221 .expect("userdata should create");
2222 globals
2223 .set("counter", &counter)
2224 .expect("userdata should register");
2225
2226 let failed = counter
2227 .with_borrow::<Counter, _>(|_| lua.load("return counter:inc(1)").eval::<i64>().is_err())
2228 .expect("outer borrow should succeed");
2229 assert!(
2230 failed,
2231 "mutable method should fail while immutable borrow is held"
2232 );
2233 assert_eq!(
2234 counter
2235 .with_borrow::<Counter, _>(|counter| counter.value)
2236 .expect("borrow should work"),
2237 1
2238 );
2239 }
2240
2241 #[test]
2242 fn userdata_index_and_newindex_metamethods_dispatch() {
2243 let lua = Lua::new();
2244 let globals = lua.globals();
2245 let bag = lua
2246 .create_userdata(PropertyBag { value: 7 })
2247 .expect("userdata should create");
2248 globals.set("bag", &bag).expect("userdata should register");
2249
2250 let result: i64 = lua
2251 .load("bag.value = 42; return bag.value")
2252 .eval()
2253 .expect("metamethods should dispatch");
2254 assert_eq!(result, 42);
2255 assert_eq!(
2256 bag.with_borrow::<PropertyBag, _>(|bag| bag.value)
2257 .expect("borrow should work"),
2258 42
2259 );
2260 }
2261
2262 #[test]
2263 fn userdata_values_convert_directly_with_into_lua() {
2264 let lua = Lua::new();
2265 let globals = lua.globals();
2266 globals
2267 .set("counter", Counter { value: 3 })
2268 .expect("userdata should convert through IntoLua");
2269
2270 let result: i64 = lua
2271 .load("counter:inc(4); return counter:get()")
2272 .eval()
2273 .expect("converted userdata should dispatch methods");
2274 assert_eq!(result, 7);
2275 }
2276
2277 #[test]
2278 fn variadic_args_and_returns_convert_all_values() {
2279 let lua = Lua::new();
2280 let globals = lua.globals();
2281
2282 let sum = lua
2283 .create_function(|_lua, values: Variadic<i64>| Ok(values.iter().sum::<i64>()))
2284 .expect("variadic callback should create");
2285 globals.set("sum", sum).expect("callback should register");
2286 let result: i64 = lua
2287 .load("return sum(3, 2, 5)")
2288 .eval()
2289 .expect("variadic callback should run");
2290 assert_eq!(result, 10);
2291
2292 let echo = lua
2293 .create_function(|_lua, values: Variadic<Value>| Ok(values))
2294 .expect("variadic return callback should create");
2295 globals.set("echo", echo).expect("callback should register");
2296 let result: (i64, i64, i64) = lua
2297 .load("return echo(1, 2, 3)")
2298 .eval()
2299 .expect("variadic returns should stay separate");
2300 assert_eq!(result, (1, 2, 3));
2301
2302 let values: Variadic<i64> = lua
2303 .load("return 4, 5, 6")
2304 .eval()
2305 .expect("variadic eval should collect all returns");
2306 assert_eq!(values.into_vec(), vec![4, 5, 6]);
2307 }
2308
2309 #[test]
2310 fn vectors_maps_and_triple_returns_convert_through_tables() {
2311 let lua = Lua::new();
2312 let globals = lua.globals();
2313
2314 globals
2315 .set("list", vec![1_i64, 2, 3])
2316 .expect("vector should convert to table");
2317 let second: i64 = lua
2318 .load("return list[2]")
2319 .eval()
2320 .expect("table should be readable from Lua");
2321 assert_eq!(second, 2);
2322
2323 let list: Vec<i64> = lua
2324 .load("return {4, 5, 6}")
2325 .eval()
2326 .expect("table should convert to vector");
2327 assert_eq!(list, vec![4, 5, 6]);
2328
2329 let mut map = HashMap::new();
2330 map.insert("left".to_string(), 10_i64);
2331 map.insert("right".to_string(), 20_i64);
2332 globals
2333 .set("map", map)
2334 .expect("map should convert to table");
2335 let sum: i64 = lua
2336 .load("return map.left + map.right")
2337 .eval()
2338 .expect("map table should be readable from Lua");
2339 assert_eq!(sum, 30);
2340
2341 let map: HashMap<String, i64> = lua
2342 .load("return {alpha = 3, beta = 9}")
2343 .eval()
2344 .expect("table should convert to map");
2345 assert_eq!(map.get("alpha"), Some(&3));
2346 assert_eq!(map.get("beta"), Some(&9));
2347
2348 let triple: (i64, i64, i64) = lua
2349 .load("return 1, 2, 3")
2350 .eval()
2351 .expect("triple returns should convert");
2352 assert_eq!(triple, (1, 2, 3));
2353 }
2354}