tlua/lib.rs
1#![allow(clippy::let_and_return)]
2#![allow(clippy::approx_constant)]
3#![allow(clippy::needless_return)]
4#![allow(clippy::redundant_closure_call)]
5#![allow(clippy::len_without_is_empty)]
6#![allow(clippy::unnecessary_cast)]
7//! High-level zero-cost bindings for Lua (fork of
8//! [hlua](https://crates.io/crates/hlua))
9//!
10//! Lua is an interpreted programming language. This crate allows you to execute Lua code.
11//!
12//! # General usage
13//!
14//! In order to execute Lua code you first need a *Lua context*, which is represented in this
15//! library with [the `Lua` struct](struct.Lua.html). You can then call the
16//! the [`eval`](struct.Lua.html#method.eval) or
17//! [`exec`](struct.Lua.html#method.exec) method on this object.
18//!
19//! For example:
20//!
21//! ```no_run
22//! use tlua::Lua;
23//!
24//! let mut lua = Lua::new();
25//! lua.exec("a = 12 * 5").unwrap();
26//! let a: u32 = lua.eval("return a + 1").unwrap();
27//! ```
28//!
29//! This example puts the value `60` in the global variable `a`. The values of all global variables
30//! are stored within the `Lua` struct. If you execute multiple Lua scripts on the same context,
31//! each script will have access to the same global variables that were modified by the previous
32//! scripts.
33//!
34//! In order to do something actually useful with Lua, we will need to make Lua and Rust
35//! communicate with each other. This can be done in four ways:
36//!
37//! - You can use methods on the `Lua` struct to read or write the values of global variables with
38//! the [`get`](struct.Lua.html#method.get) and [`set`](struct.Lua.html#method.set) methods. For
39//! example you can write to a global variable with a Lua script then read it from Rust, or you
40//! can write to a global variable from Rust then read it from a Lua script.
41//!
42//! - The Lua script that you evaluate with the [`eval`](struct.Lua.html#method.eval) method
43//! can return a value.
44//!
45//! - You can set the value of a global variable to a Rust functions or closures, which can then be
46//! invoked with a Lua script. See [the `Function` struct](struct.Function.html) for more
47//! information. For example if you set the value of the global variable `foo` to a Rust
48//! function, you can then call it from Lua with `foo()`.
49//!
50//! - Similarly you can set the value of a global variable to a Lua function, then call it from
51//! Rust. The function call can return a value.
52//!
53//! Which method(s) you use depends on which API you wish to expose to your Lua scripts.
54//!
55//! # Pushing and loading values
56//!
57//! The interface between Rust and Lua involves two things:
58//!
59//! - Sending values from Rust to Lua, which is known as *pushing* the value.
60//! - Sending values from Lua to Rust, which is known as *loading* the value.
61//!
62//! Pushing (ie. sending from Rust to Lua) can be done with
63//! [the `set` method](struct.Lua.html#method.set):
64//!
65//! ```no_run
66//! let lua = tlua::Lua::new();
67//! lua.set("a", 50);
68//! ```
69//!
70//! You can push values that implement [the `Push` trait](trait.Push.html) or
71//! [the `PushOne` trait](trait.PushOne.html) depending on the situation:
72//!
73//! - Integers, floating point numbers and booleans.
74//! - `String` and `&str`.
75//! - Any Rust function or closure whose parameters and loadable and whose return type is pushable.
76//! See the documentation of [the `Function` struct](struct.Function.html) for more information.
77//! - [The `AnyLuaValue` struct](struct.AnyLuaValue.html). This enumeration represents any possible
78//! value in Lua.
79//! - The [`LuaCode`](struct.LuaCode.html) and
80//! [`LuaCodeFromReader`](struct.LuaCodeFromReader.html) structs. Since pushing these structs can
81//! result in an error, you need to use [`checked_set`](struct.Lua.html#method.checked_set)
82//! instead of `set`.
83//! - `Vec`s and `HashMap`s whose content is pushable.
84//! - As a special case, `Result` can be pushed only as the return type of a Rust function or
85//! closure. If they contain an error, the Rust function call is considered to have failed.
86//! - As a special case, tuples can be pushed when they are the return type of a Rust function or
87//! closure. They implement `Push` but not `PushOne`.
88//! - TODO: userdata
89//!
90//! Loading (ie. sending from Lua to Rust) can be done with
91//! [the `get` method](struct.Lua.html#method.get):
92//!
93//! ```no_run
94//! # use tlua::Lua;
95//! # let lua = Lua::new();
96//! let a: i32 = lua.get("a").unwrap();
97//! ```
98//!
99//! You can load values that implement [the `LuaRead` trait](trait.LuaRead.html):
100//!
101//! - Integers, floating point numbers and booleans.
102//! - `String` and [`StringInLua`](struct.StringInLua.html) (ie. the equivalent of `&str`). Loading
103//! the latter has no cost while loading a `String` performs an allocation.
104//! - Any function (Lua or Rust), with [the `LuaFunction` struct](struct.LuaFunction.html). This
105//! can then be used to execute the function.
106//! - [The `AnyLuaValue` struct](struct.AnyLuaValue.html). This enumeration represents any possible
107//! value in Lua.
108//! - [The `LuaTable` struct](struct.LuaTable.html). This struct represents a table in Lua, where
109//! keys and values can be of different types. The table can then be iterated and individual
110//! elements can be loaded or modified.
111//! - As a special case, tuples can be loaded when they are the return type of a Lua function or as
112//! the return type of [`eval`](struct.Lua.html#method.eval).
113//! - TODO: userdata
114//!
115use std::borrow::{Borrow, Cow};
116use std::collections::LinkedList;
117use std::ffi::{CStr, CString};
118use std::fmt;
119use std::io::Read;
120use std::io::{self, Write};
121use std::num::NonZeroI32;
122
123pub use ::tlua_derive::*;
124
125/// The recommended way to describe tests in `tlua` crate
126///
127/// # Example
128/// ```skip
129/// #[tlua::test]
130/// fn my_test() {
131/// assert!(true);
132/// }
133/// ```
134pub use ::tlua_derive::test;
135
136pub use any::{AnyHashableLuaValue, AnyLuaString, AnyLuaValue};
137pub use cdata::{AsCData, CData, CDataOnStack};
138pub use functions_write::{
139 function0, function1, function10, function2, function3, function4, function5, function6,
140 function7, function8, function9, protected_call, CFunction, Function, InsideCallback, Throw,
141};
142pub use lua_functions::LuaFunction;
143pub use lua_functions::{LuaCode, LuaCodeFromReader};
144pub use lua_tables::{LuaTable, LuaTableIterator};
145pub use object::{
146 Call, CallError, Callable, Index, Indexable, IndexableRW, MethodCallError, NewIndex, Object,
147};
148pub use rust_tables::{PushIterError, PushIterErrorOf, TableFromIter};
149pub use tuples::{AsTable, TuplePushError};
150pub use userdata::UserdataOnStack;
151pub use userdata::{push_some_userdata, push_userdata, read_userdata};
152pub use values::BytesInLua;
153pub use values::{False, Nil, Null, Strict, StringInLua, ToString, True, Typename};
154
155#[deprecated = "Use `CallError` instead"]
156pub type LuaFunctionCallError<E> = CallError<E>;
157pub type LuaTableMap = std::collections::HashMap<AnyHashableLuaValue, AnyLuaValue>;
158pub type LuaSequence = Vec<AnyLuaValue>;
159
160mod any;
161mod cdata;
162pub mod debug;
163pub mod ffi;
164mod functions_write;
165mod lua_functions;
166mod lua_tables;
167mod macros;
168mod object;
169mod rust_tables;
170#[cfg(feature = "extra_impls")]
171mod smol_str;
172#[cfg(feature = "internal_test")]
173pub mod test;
174mod tuples;
175mod userdata;
176pub mod util;
177mod values;
178
179pub type LuaState = *mut ffi::lua_State;
180
181/// A static lua context that must be created from an existing lua state pointer
182/// and that will **not** be closed when dropped.
183pub type StaticLua = Lua<on_drop::Ignore>;
184
185/// A temporary lua context that will be closed when dropped.
186pub type TempLua = Lua<on_drop::Close>;
187
188/// A lua context corresponding to a lua thread (see [`ffi::lua_newthread`])
189/// stored in the global [REGISTRY](ffi::LUA_REGISTRYINDEX) and will be removed
190/// from there when dropped.
191///
192/// `LuaThread` currently can only be created from an instance of [`StaticLua`]
193/// because closing a state from which a thread has been created is forbidden.
194pub type LuaThread = Lua<on_drop::Unref>;
195
196/// Main object of the library.
197///
198/// The type parameter `OnDrop` specifies what happens with the underlying lua
199/// state when the instance gets dropped. There are currently 3 supported cases:
200/// - `on_drop::Ignore`: nothing happens
201/// - `on_drop::Close`: [`ffi::lua_close`] is called
202/// - `on_drop::Unref`: [`ffi::luaL_unref`] is called with the associated value
203///
204/// # About panic safety
205///
206/// This type isn't panic safe. This means that if a panic happens while you were using the `Lua`,
207/// then it will probably stay in a corrupt state. Trying to use the `Lua` again will most likely
208/// result in another panic but shouldn't result in unsafety.
209#[derive(Debug)]
210pub struct Lua<OnDrop>
211where
212 OnDrop: on_drop::OnDrop,
213{
214 lua: LuaState,
215 on_drop: OnDrop,
216}
217
218mod on_drop {
219 use crate::{ffi, LuaState};
220
221 pub trait OnDrop {
222 fn on_drop(&mut self, l: LuaState);
223 }
224
225 /// See [`StaticLua`].
226 #[derive(Debug)]
227 pub struct Ignore;
228
229 impl OnDrop for Ignore {
230 fn on_drop(&mut self, _: LuaState) {}
231 }
232
233 /// See [`TempLua`].
234 #[derive(Debug)]
235 pub struct Close;
236
237 impl OnDrop for Close {
238 fn on_drop(&mut self, l: LuaState) {
239 unsafe { ffi::lua_close(l) }
240 }
241 }
242
243 /// See [`LuaThread`].
244 #[derive(Debug)]
245 pub struct Unref(pub i32);
246
247 impl OnDrop for Unref {
248 fn on_drop(&mut self, l: LuaState) {
249 unsafe { ffi::luaL_unref(l, ffi::LUA_REGISTRYINDEX, self.0) }
250 }
251 }
252}
253
254/// RAII guard for a value pushed on the stack.
255///
256/// You shouldn't have to manipulate this type directly unless you are fiddling with the
257/// library's internals.
258pub struct PushGuard<L>
259where
260 L: AsLua,
261{
262 lua: L,
263 top: i32,
264 size: i32,
265}
266
267impl<L> std::fmt::Debug for PushGuard<L>
268where
269 L: AsLua,
270 L: std::fmt::Debug,
271{
272 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273 let start = unsafe {
274 AbsoluteIndex::new_unchecked(NonZeroI32::new(self.top - self.size + 1).unwrap())
275 };
276 f.debug_struct("PushGuard")
277 .field("lua", &self.lua)
278 .field("size", &self.size)
279 .field(
280 "lua_type",
281 &typenames(self.lua.as_lua(), start, self.size as _),
282 )
283 .finish()
284 }
285}
286
287impl<L: AsLua> PushGuard<L> {
288 /// Creates a new `PushGuard` from this Lua context representing `size` items on the stack.
289 /// When this `PushGuard` is destroyed, `size` items will be popped.
290 ///
291 /// # Safety
292 /// There must be at least `size` elements on the `lua` stack and it must be
293 /// safe to drop them at the same time with this `PushGuard`.
294 #[inline]
295 pub unsafe fn new(lua: L, size: i32) -> Self {
296 PushGuard {
297 top: ffi::lua_gettop(lua.as_lua()),
298 lua,
299 size: size as _,
300 }
301 }
302
303 #[inline]
304 pub fn assert_one_and_forget(self) -> i32 {
305 assert_eq!(self.size, 1);
306 self.forget_internal()
307 }
308
309 /// Returns the number of elements managed by this `PushGuard`.
310 #[inline]
311 pub fn size(&self) -> i32 {
312 self.size
313 }
314
315 /// Prevents the value from being popped when the `PushGuard` is destroyed, and returns the
316 /// number of elements on the Lua stack.
317 ///
318 /// # Safety
319 /// The values on the stack will not be popped automatically, so the caller
320 /// must ensure nothing is leaked.
321 #[inline]
322 pub unsafe fn forget(self) -> i32 {
323 self.forget_internal()
324 }
325
326 /// Internal crate-only version of `forget`. It is generally assumed that code within this
327 /// crate that calls this method knows what it is doing.
328 #[inline]
329 fn forget_internal(mut self) -> i32 {
330 let size = self.size;
331 self.size = 0;
332 size
333 }
334
335 /// Destroys the guard, popping the value. Returns the inner part,
336 /// which returns access when using by-value capture.
337 #[inline]
338 pub fn into_inner(self) -> L {
339 use std::{
340 mem::{self, MaybeUninit},
341 ptr,
342 };
343
344 let mut res = MaybeUninit::uninit();
345 unsafe {
346 ptr::copy_nonoverlapping(&self.lua, res.as_mut_ptr(), 1);
347 if self.size != 0 {
348 ffi::lua_pop(self.lua.as_lua(), self.size as _);
349 }
350 };
351 mem::forget(self);
352
353 unsafe { res.assume_init() }
354 }
355}
356
357/// Trait for objects that have access to a Lua context.
358pub trait AsLua {
359 fn as_lua(&self) -> *mut ffi::lua_State;
360
361 /// Try to push `v` onto the lua stack.
362 ///
363 /// In case of success returns a `PushGuard` which captures `self` by value
364 /// and stores the amount of values pushed onto the stack.
365 ///
366 /// In case of failure returns a tuple with 2 elements:
367 /// - an error, which occured during the attempt to push
368 /// - `self`
369 #[inline(always)]
370 fn try_push<T>(self, v: T) -> Result<PushGuard<Self>, (<T as PushInto<Self>>::Err, Self)>
371 where
372 Self: Sized,
373 T: PushInto<Self>,
374 {
375 v.push_into_lua(self)
376 }
377
378 /// Push `v` onto the lua stack.
379 ///
380 /// This method is only available if `T::Err` implements `Into<Void>`, which
381 /// means that no error can happen during the attempt to push.
382 ///
383 /// Returns a `PushGuard` which captures `self` by value and stores the
384 /// amount of values pushed onto the stack.
385 #[inline(always)]
386 fn push<T>(self, v: T) -> PushGuard<Self>
387 where
388 Self: Sized,
389 T: PushInto<Self>,
390 <T as PushInto<Self>>::Err: Into<Void>,
391 {
392 v.push_into_no_err(self)
393 }
394
395 /// Try to push `v` onto the lua stack.
396 ///
397 /// This method is only available if `T` implements `PushOneInto`, which
398 /// means that it pushes a single value onto the stack.
399 ///
400 /// Returns a `PushGuard` which captures `self` by value and stores the
401 /// amount of values pushed onto the stack (ideally this will be 1, but it
402 /// is the responsibility of the impelemntor to make sure it is so).
403 #[inline(always)]
404 fn try_push_one<T>(self, v: T) -> Result<PushGuard<Self>, (<T as PushInto<Self>>::Err, Self)>
405 where
406 Self: Sized,
407 T: PushOneInto<Self>,
408 {
409 v.push_into_lua(self)
410 }
411
412 /// Push `v` onto the lua stack.
413 ///
414 /// This method is only available if
415 /// - `T` implements `PushOneInto`, which means that it pushes a single value onto the stack
416 /// - `T::Err` implements `Into<Void>`, which means that no error can happen during the attempt to push
417 ///
418 /// Returns a `PushGuard` which captures `self` by value and stores the
419 /// amount of values pushed onto the stack (ideally this will be 1, but it
420 /// is the responsibility of the impelemntor to make sure it is so).
421 #[inline(always)]
422 fn push_one<T>(self, v: T) -> PushGuard<Self>
423 where
424 Self: Sized,
425 T: PushOneInto<Self>,
426 <T as PushInto<Self>>::Err: Into<Void>,
427 {
428 v.push_into_no_err(self)
429 }
430
431 /// Push `iterator` onto the lua stack as a lua table.
432 ///
433 /// This method is only available if
434 /// - `I::Item` implements `PushInto<LuaState>`, which means that it can be
435 /// pushed onto the lua stack by value
436 /// - `I::Item::Err` implements `Into<Void>`, which means that no error can
437 /// happen during the attempt to push
438 ///
439 /// If `I::Item` pushes a single value onto the stack, the resulting lua
440 /// table is a lua sequence (a table with 1-based integer keys).
441 ///
442 /// If `I::Item` pushes 2 values onto the stack, the resulting lua table is
443 /// a regular lua table with the provided keys.
444 ///
445 /// If `I::Item` pushes more than 2 values, the function returns `Err(self)`.
446 ///
447 /// Returns a `PushGuard` which captures `self` by value and stores the
448 /// amount of values pushed onto the stack (exactly 1 -- lua table).
449 #[inline(always)]
450 fn push_iter<I>(self, iterator: I) -> Result<PushGuard<Self>, Self>
451 where
452 Self: Sized,
453 I: Iterator,
454 <I as Iterator>::Item: PushInto<LuaState>,
455 <<I as Iterator>::Item as PushInto<LuaState>>::Err: Into<Void>,
456 {
457 rust_tables::push_iter(self, iterator).map_err(|(_, lua)| lua)
458 }
459
460 /// Push `iterator` onto the lua stack as a lua table.
461 ///
462 /// This method is only available if `I::Item` implements
463 /// `PushInto<LuaState>`, which means that it can be pushed onto the lua
464 /// stack by value.
465 ///
466 /// If `I::Item` pushes a single value onto the stack, the resulting lua
467 /// table is a lua sequence (a table with 1-based integer keys).
468 ///
469 /// If `I::Item` pushes 2 values onto the stack, the resulting lua table is
470 /// a regular lua table with the provided keys.
471 ///
472 /// If `I::Item` pushes more than 2 values or an error happens during an
473 /// attempt to push, the function returns `Err((e, self))` where `e` is a
474 /// `PushIterErrorOf`.
475 ///
476 /// Returns a `PushGuard` which captures `self` by value and stores the
477 /// amount of values pushed onto the stack (exactly 1 -- lua table).
478 #[inline(always)]
479 fn try_push_iter<I>(self, iterator: I) -> Result<PushGuard<Self>, (PushIterErrorOf<I>, Self)>
480 where
481 Self: Sized,
482 I: Iterator,
483 <I as Iterator>::Item: PushInto<LuaState>,
484 {
485 rust_tables::push_iter(self, iterator)
486 }
487
488 #[inline(always)]
489 fn read<T>(self) -> ReadResult<T, Self>
490 where
491 Self: Sized,
492 T: LuaRead<Self>,
493 {
494 T::lua_read(self)
495 }
496
497 #[inline(always)]
498 fn read_at<T>(self, index: i32) -> ReadResult<T, Self>
499 where
500 Self: Sized,
501 T: LuaRead<Self>,
502 {
503 T::lua_read_at_maybe_zero_position(self, index)
504 }
505
506 #[inline(always)]
507 fn read_at_nz<T>(self, index: NonZeroI32) -> ReadResult<T, Self>
508 where
509 Self: Sized,
510 T: LuaRead<Self>,
511 {
512 T::lua_read_at_position(self, index)
513 }
514
515 /// Call a rust function in protected mode. If a lua error is thrown during
516 /// execution of `f` the function will return a `LuaError`.
517 ///
518 /// This can also be sometimes used to catch other C++ exceptions although
519 /// be careful with that.
520 #[track_caller]
521 #[inline(always)]
522 fn pcall<F, R>(&self, f: F) -> Result<R, LuaError>
523 where
524 F: FnOnce(StaticLua) -> R,
525 {
526 protected_call(self, f)
527 }
528}
529
530impl<T> AsLua for &'_ T
531where
532 T: ?Sized + AsLua,
533{
534 fn as_lua(&self) -> *mut ffi::lua_State {
535 T::as_lua(self)
536 }
537}
538
539impl<D> AsLua for Lua<D>
540where
541 D: on_drop::OnDrop,
542{
543 #[inline]
544 fn as_lua(&self) -> *mut ffi::lua_State {
545 self.lua
546 }
547}
548
549impl AsLua for *mut ffi::lua_State {
550 fn as_lua(&self) -> *mut ffi::lua_State {
551 *self
552 }
553}
554
555impl<L> AsLua for PushGuard<L>
556where
557 L: AsLua,
558{
559 #[inline]
560 fn as_lua(&self) -> *mut ffi::lua_State {
561 self.lua.as_lua()
562 }
563}
564
565/// Type returned from [`Push::push_to_lua`] function.
566pub type PushResult<L, P> = Result<PushGuard<L>, (<P as Push<L>>::Err, L)>;
567
568/// Types implementing this trait can be pushed onto the Lua stack by reference.
569pub trait Push<L: AsLua> {
570 /// Error that can happen when pushing a value.
571 type Err;
572
573 /// Pushes the value on the top of the stack.
574 ///
575 /// Must return a guard representing the elements that have been pushed.
576 ///
577 /// You can implement this for any type you want by redirecting to call to
578 /// another implementation (for example `5.push_to_lua`) or by calling
579 /// `userdata::push_userdata`.
580 fn push_to_lua(&self, lua: L) -> Result<PushGuard<L>, (Self::Err, L)>;
581
582 /// Same as `push_to_lua` but can only succeed and is only available if
583 /// `Err` implements `Into<Void>`.
584 #[inline]
585 fn push_no_err(&self, lua: L) -> PushGuard<L>
586 where
587 <Self as Push<L>>::Err: Into<Void>,
588 {
589 match self.push_to_lua(lua) {
590 Ok(p) => p,
591 Err(_) => unreachable!("no way to instantiate Void"),
592 }
593 }
594}
595
596impl<T, L> Push<L> for &'_ T
597where
598 L: AsLua,
599 T: ?Sized,
600 T: Push<L>,
601{
602 type Err = T::Err;
603
604 fn push_to_lua(&self, lua: L) -> Result<PushGuard<L>, (Self::Err, L)> {
605 T::push_to_lua(*self, lua)
606 }
607}
608
609/// Extension trait for `Push`. Guarantees that only one element will be pushed.
610///
611/// This should be implemented on most types that implement `Push`, except for tuples.
612///
613/// > **Note**: Implementing this trait on a type that pushes multiple elements will most likely
614/// > result in panics.
615// Note for the implementation: since this trait is not unsafe, it is mostly a hint. Functions can
616// require this trait if they only accept one pushed element, but they must also add a runtime
617// assertion to make sure that only one element was actually pushed.
618pub trait PushOne<L: AsLua>: Push<L> {}
619
620impl<T, L> PushOne<L> for &'_ T
621where
622 L: AsLua,
623 T: ?Sized,
624 T: PushOne<L>,
625{
626}
627
628/// Type returned from [`PushInto::push_into_lua`] function.
629pub type PushIntoResult<L, P> = Result<PushGuard<L>, (<P as PushInto<L>>::Err, L)>;
630
631/// Types implementing this trait can be pushed onto the Lua stack by value.
632pub trait PushInto<L>
633where
634 L: AsLua,
635{
636 type Err;
637
638 /// Push the value into lua by value
639 fn push_into_lua(self, lua: L) -> Result<PushGuard<L>, (Self::Err, L)>;
640
641 /// Same as `push_into_lua` but can only succeed and is only available if
642 /// `Err` implements `Into<Void>`.
643 #[inline]
644 fn push_into_no_err(self, lua: L) -> PushGuard<L>
645 where
646 Self: Sized,
647 <Self as PushInto<L>>::Err: Into<Void>,
648 {
649 match self.push_into_lua(lua) {
650 Ok(p) => p,
651 Err(_) => unreachable!("no way to instantiate Void"),
652 }
653 }
654}
655
656impl<T, L> PushInto<L> for &'_ T
657where
658 L: AsLua,
659 T: ?Sized,
660 T: Push<L>,
661{
662 type Err = T::Err;
663
664 fn push_into_lua(self, lua: L) -> Result<PushGuard<L>, (Self::Err, L)> {
665 self.push_to_lua(lua)
666 }
667}
668
669/// Extension trait for `PushInto`. Guarantees that only one element will be
670/// pushed.
671///
672/// This should be implemented on most types that implement `PushInto`, except
673/// for tuples.
674///
675/// > **Note**: Implementing this trait on a type that pushes multiple elements
676/// > will most likely result in panics.
677///
678// Note for the implementation: since this trait is not unsafe, it is mostly a
679// hint. Functions can require this trait if they only accept one pushed
680// element, but they must also add a runtime assertion to make sure that only
681// one element was actually pushed.
682pub trait PushOneInto<L: AsLua>: PushInto<L> {}
683
684impl<T, L> PushOneInto<L> for &'_ T
685where
686 L: AsLua,
687 T: ?Sized,
688 T: PushOne<L>,
689{
690}
691
692/// Type that cannot be instantiated.
693///
694/// Will be replaced with `!` eventually (<https://github.com/rust-lang/rust/issues/35121>).
695#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
696pub enum Void {}
697
698impl fmt::Display for Void {
699 fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
700 unreachable!("Void cannot be instantiated")
701 }
702}
703
704pub const NEGATIVE_ONE: NonZeroI32 = NonZeroI32::new(-1).unwrap();
705pub const NEGATIVE_TWO: NonZeroI32 = NonZeroI32::new(-2).unwrap();
706
707////////////////////////////////////////////////////////////////////////////////
708// LuaRead
709////////////////////////////////////////////////////////////////////////////////
710
711/// Types that can be obtained from a Lua context.
712///
713/// Most types that implement `Push` also implement `LuaRead`, but this is not always the case
714/// (for example `&'static str` implements `Push` but not `LuaRead`).
715pub trait LuaRead<L>: Sized {
716 #[inline(always)]
717 fn n_values_expected() -> i32 {
718 1
719 }
720
721 /// Reads the data from Lua.
722 #[inline]
723 fn lua_read(lua: L) -> ReadResult<Self, L> {
724 let index = NonZeroI32::new(-Self::n_values_expected()).expect("Invalid n_values_expected");
725 Self::lua_read_at_position(lua, index)
726 }
727
728 fn lua_read_at_maybe_zero_position(lua: L, index: i32) -> ReadResult<Self, L>
729 where
730 L: AsLua,
731 {
732 if let Some(index) = NonZeroI32::new(index) {
733 Self::lua_read_at_position(lua, index)
734 } else {
735 let e = WrongType::default()
736 .expected_type::<Self>()
737 .actual("no value");
738 Err((lua, e))
739 }
740 }
741
742 /// Reads the data from Lua at a given position.
743 fn lua_read_at_position(lua: L, index: NonZeroI32) -> ReadResult<Self, L>;
744}
745
746pub type ReadResult<T, L> = Result<T, (L, WrongType)>;
747
748impl<L: AsLua> LuaRead<L> for LuaState {
749 fn lua_read_at_maybe_zero_position(lua: L, _: i32) -> ReadResult<Self, L> {
750 Ok(lua.as_lua())
751 }
752
753 fn lua_read_at_position(lua: L, _: NonZeroI32) -> ReadResult<Self, L> {
754 Ok(lua.as_lua())
755 }
756}
757
758////////////////////////////////////////////////////////////////////////////////
759// LuaError
760////////////////////////////////////////////////////////////////////////////////
761
762/// Error that can happen when executing Lua code.
763#[derive(Debug, thiserror::Error)]
764pub enum LuaError {
765 /// There was a syntax error when parsing the Lua code.
766 #[error("syntax error: {0}")]
767 SyntaxError(String),
768
769 /// There was an error during execution of the Lua code
770 /// (for example not enough parameters for a function call).
771 #[error("{0}")]
772 ExecutionError(Cow<'static, str>),
773
774 /// There was an IoError while reading the source code to execute.
775 #[error("{0}")]
776 ReadError(#[from] io::Error),
777
778 /// The call to `eval` has requested the wrong type of data.
779 #[error("{0}")]
780 WrongType(#[from] WrongType),
781}
782
783////////////////////////////////////////////////////////////////////////////////
784// WrongType
785////////////////////////////////////////////////////////////////////////////////
786
787#[derive(Debug, thiserror::Error)]
788pub struct WrongType {
789 when: &'static str,
790 rust_expected: String,
791 lua_actual: String,
792 subtypes: LinkedList<WrongType>,
793}
794
795impl<E> From<WrongType> for CallError<E> {
796 fn from(e: WrongType) -> Self {
797 Self::LuaError(e.into())
798 }
799}
800
801impl Default for WrongType {
802 fn default() -> Self {
803 Self {
804 when: "reading Lua value",
805 rust_expected: Default::default(),
806 lua_actual: Default::default(),
807 subtypes: Default::default(),
808 }
809 }
810}
811
812impl fmt::Display for WrongType {
813 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
814 let subtype = crate::unwrap_or! { self.subtypes.front(),
815 write!(f, "failed ")?;
816 return display_leaf(self, f);
817 };
818
819 if subtype.subtypes.is_empty()
820 && subtype.rust_expected == self.rust_expected
821 && subtype.lua_actual == self.lua_actual
822 {
823 write!(f, "failed ")?;
824 return display_leaf(self, f);
825 }
826
827 if self.subtypes.len() == 1 {
828 write!(f, "{subtype}")?;
829 } else {
830 write!(f, "variant #1: {subtype}")?;
831 for (subtype, i) in self.subtypes.iter().skip(1).zip(2..) {
832 write!(f, "\nvariant #{i}: {subtype}")?;
833 }
834 }
835
836 write!(f, "\n while ")?;
837 display_leaf(self, f)?;
838
839 return Ok(());
840
841 fn display_leaf(wt: &WrongType, f: &mut fmt::Formatter) -> fmt::Result {
842 return write!(
843 f,
844 "{}: {} expected, got {}",
845 wt.when, wt.rust_expected, wt.lua_actual
846 );
847 }
848 }
849}
850
851impl WrongType {
852 #[inline(always)]
853 pub fn info(when: &'static str) -> Self {
854 Self {
855 when,
856 ..Self::default()
857 }
858 }
859
860 #[inline(always)]
861 pub fn when(mut self, when: &'static str) -> Self {
862 self.when = when;
863 self
864 }
865
866 #[inline(always)]
867 pub fn expected_type<T>(mut self) -> Self {
868 self.rust_expected = std::any::type_name::<T>().into();
869 self
870 }
871
872 #[inline(always)]
873 pub fn expected(mut self, expected: impl Into<String>) -> Self {
874 self.rust_expected = expected.into();
875 self
876 }
877
878 /// Set the actual Lua type from a value at `index`.
879 #[inline(always)]
880 pub fn actual_single_lua<L: AsLua>(mut self, lua: L, index: NonZeroI32) -> Self {
881 let index = AbsoluteIndex::new(index, lua.as_lua());
882 self.lua_actual = typenames(lua, index, 1);
883 self
884 }
885
886 /// Set the actual Lua type from a range of lowest `n_values` on the stack.
887 #[inline(always)]
888 #[track_caller]
889 pub fn actual_multiple_lua<L: AsLua>(self, lua: L, n_values: i32) -> Self {
890 self.actual_multiple_lua_at(lua, -n_values, n_values)
891 }
892
893 /// Set the actual Lua type from a range of `n_values` values starting at index `start`.
894 #[inline(always)]
895 #[track_caller]
896 pub fn actual_multiple_lua_at<L: AsLua>(
897 mut self,
898 lua: L,
899 start: impl Into<i32>,
900 n_values: i32,
901 ) -> Self {
902 if let Some(start) = AbsoluteIndex::try_new(start, lua.as_lua()) {
903 self.lua_actual = typenames(lua, start, n_values as _);
904 } else {
905 self.lua_actual = "no values".into()
906 }
907 self
908 }
909
910 #[inline(always)]
911 pub fn actual(mut self, actual: impl Into<String>) -> Self {
912 self.lua_actual = actual.into();
913 self
914 }
915
916 #[inline(always)]
917 pub fn subtype(mut self, subtype: Self) -> Self {
918 self.subtypes.push_back(subtype);
919 self
920 }
921
922 #[inline(always)]
923 pub fn subtypes(mut self, subtypes: LinkedList<Self>) -> Self {
924 self.subtypes = subtypes;
925 self
926 }
927}
928
929pub fn typename(lua: impl AsLua, index: i32) -> &'static CStr {
930 unsafe {
931 let lua_type = ffi::lua_type(lua.as_lua(), index);
932 let typename = ffi::lua_typename(lua.as_lua(), lua_type);
933 CStr::from_ptr(typename)
934 }
935}
936
937#[track_caller]
938pub fn typenames(lua: impl AsLua, start: AbsoluteIndex, count: u32) -> String {
939 let l_ptr = lua.as_lua();
940 let single_typename = |i| typename(l_ptr, i as _).to_string_lossy();
941
942 let start = start.get();
943 match count {
944 0 => return "()".into(),
945 1 => return single_typename(start).into_owned(),
946 _ => {}
947 }
948
949 let mut res = Vec::with_capacity(32);
950 write!(res, "(").expect("writing to vec cannot fail");
951 let end = start + count - 1;
952 for i in start..end {
953 write!(res, "{}, ", single_typename(i)).expect("writing to vec cannot fail");
954 }
955 write!(res, "{})", single_typename(end)).expect("writing to vec cannot fail");
956 // concatenation of utf8 is utf8
957 unsafe { String::from_utf8_unchecked(res) }
958}
959
960////////////////////////////////////////////////////////////////////////////////
961// impl TempLua
962////////////////////////////////////////////////////////////////////////////////
963
964impl TempLua {
965 /// Builds a new empty TempLua context.
966 ///
967 /// There are no global variables and the registry is totally empty. Even the functions from
968 /// the standard library can't be used.
969 ///
970 /// If you want to use the Lua standard library in the scripts of this context, see
971 /// [the openlibs method](#method.openlibs)
972 ///
973 /// # Example
974 ///
975 /// ```no_run
976 /// use tlua::Lua;
977 /// let lua = Lua::new();
978 /// ```
979 ///
980 /// # Panic
981 ///
982 /// The function panics if the underlying call to `lua_newstate` fails
983 /// (which indicates lack of memory).
984 #[track_caller]
985 #[inline]
986 pub fn new() -> Self {
987 let lua = unsafe { ffi::luaL_newstate() };
988 if lua.is_null() {
989 panic!("lua_newstate failed");
990 }
991
992 // called whenever lua encounters an unexpected error.
993 extern "C-unwind" fn panic(lua: *mut ffi::lua_State) -> libc::c_int {
994 let err = unsafe { ffi::lua_tostring(lua, -1) };
995 let err = unsafe { CStr::from_ptr(err) };
996 let err = String::from_utf8(err.to_bytes().to_vec()).unwrap();
997 panic!("PANIC: unprotected error in call to Lua API ({})\n", err);
998 }
999
1000 unsafe { ffi::lua_atpanic(lua, panic) };
1001
1002 unsafe { Self::from_existing(lua) }
1003 }
1004
1005 /// Takes an existing `lua_State` and build a TemplLua object from it.
1006 ///
1007 /// `lua_close` will be called on the `lua_State` in drop.
1008 ///
1009 /// # Safety
1010 /// A pointer to a valid `lua` context must be provided which is ok to be
1011 /// closed.
1012 #[inline]
1013 pub unsafe fn from_existing<T>(lua: *mut T) -> Self {
1014 Self {
1015 lua: lua as _,
1016 on_drop: on_drop::Close,
1017 }
1018 }
1019}
1020
1021impl StaticLua {
1022 /// Takes an existing `lua_State` and build a StaticLua object from it.
1023 ///
1024 /// `lua_close` is **NOT** called in `drop`.
1025 ///
1026 /// # Safety
1027 /// A pointer to a valid `lua` context must be provided.
1028 #[inline]
1029 pub unsafe fn from_static<T>(lua: *mut T) -> Self {
1030 Self {
1031 lua: lua as _,
1032 on_drop: on_drop::Ignore,
1033 }
1034 }
1035
1036 /// Creates a new Lua thread with an independent stack and runs the provided
1037 /// function within it. The new state has access to all the global objects
1038 /// available to `self`.
1039 pub fn new_thread(&self) -> LuaThread {
1040 unsafe {
1041 let lua = ffi::lua_newthread(self.as_lua());
1042 let r = ffi::luaL_ref(self.as_lua(), ffi::LUA_REGISTRYINDEX);
1043 LuaThread {
1044 lua,
1045 on_drop: on_drop::Unref(r),
1046 }
1047 }
1048 }
1049}
1050
1051impl<L: AsLua> LuaRead<L> for StaticLua {
1052 fn lua_read_at_maybe_zero_position(lua: L, _: i32) -> ReadResult<Self, L> {
1053 Ok(Self {
1054 lua: lua.as_lua(),
1055 on_drop: on_drop::Ignore,
1056 })
1057 }
1058
1059 fn lua_read_at_position(lua: L, _: NonZeroI32) -> ReadResult<Self, L> {
1060 Ok(Self {
1061 lua: lua.as_lua(),
1062 on_drop: on_drop::Ignore,
1063 })
1064 }
1065}
1066
1067impl<OnDrop> Lua<OnDrop>
1068where
1069 OnDrop: on_drop::OnDrop,
1070{
1071 /// Opens all standard Lua libraries.
1072 ///
1073 /// See the reference for the standard library here:
1074 /// <https://www.lua.org/manual/5.2/manual.html#6>
1075 ///
1076 /// This is done by calling `luaL_openlibs`.
1077 ///
1078 /// # Example
1079 ///
1080 /// ```no_run
1081 /// use tlua::Lua;
1082 /// let lua = Lua::new();
1083 /// lua.openlibs();
1084 /// ```
1085 #[inline]
1086 // TODO(gmoshkin): this method should be part of AsLua
1087 pub fn openlibs(&self) {
1088 unsafe { ffi::luaL_openlibs(self.lua) }
1089 }
1090
1091 /// Opens base library.
1092 ///
1093 /// <https://www.lua.org/manual/5.2/manual.html#pdf-luaopen_base>
1094 #[inline]
1095 // TODO(gmoshkin): this method should be part of AsLua
1096 pub fn open_base(&self) {
1097 unsafe { ffi::luaopen_base(self.lua) }
1098 }
1099
1100 /// Opens bit32 library.
1101 ///
1102 /// <https://www.lua.org/manual/5.2/manual.html#pdf-luaopen_bit32>
1103 #[inline]
1104 // TODO(gmoshkin): this method should be part of AsLua
1105 pub fn open_bit(&self) {
1106 unsafe { ffi::luaopen_bit(self.lua) }
1107 }
1108
1109 /// Opens debug library.
1110 ///
1111 /// <https://www.lua.org/manual/5.2/manual.html#pdf-luaopen_debug>
1112 #[inline]
1113 // TODO(gmoshkin): this method should be part of AsLua
1114 pub fn open_debug(&self) {
1115 unsafe { ffi::luaopen_debug(self.lua) }
1116 }
1117
1118 /// Opens io library.
1119 ///
1120 /// <https://www.lua.org/manual/5.2/manual.html#pdf-luaopen_io>
1121 #[inline]
1122 // TODO(gmoshkin): this method should be part of AsLua
1123 pub fn open_io(&self) {
1124 unsafe { ffi::luaopen_io(self.lua) }
1125 }
1126
1127 /// Opens math library.
1128 ///
1129 /// <https://www.lua.org/manual/5.2/manual.html#pdf-luaopen_math>
1130 #[inline]
1131 // TODO(gmoshkin): this method should be part of AsLua
1132 pub fn open_math(&self) {
1133 unsafe { ffi::luaopen_math(self.lua) }
1134 }
1135
1136 /// Opens os library.
1137 ///
1138 /// <https://www.lua.org/manual/5.2/manual.html#pdf-luaopen_os>
1139 #[inline]
1140 // TODO(gmoshkin): this method should be part of AsLua
1141 pub fn open_os(&self) {
1142 unsafe { ffi::luaopen_os(self.lua) }
1143 }
1144
1145 /// Opens package library.
1146 ///
1147 /// <https://www.lua.org/manual/5.2/manual.html#pdf-luaopen_package>
1148 #[inline]
1149 // TODO(gmoshkin): this method should be part of AsLua
1150 pub fn open_package(&self) {
1151 unsafe { ffi::luaopen_package(self.lua) }
1152 }
1153
1154 /// Opens string library.
1155 ///
1156 /// <https://www.lua.org/manual/5.2/manual.html#pdf-luaopen_string>
1157 #[inline]
1158 // TODO(gmoshkin): this method should be part of AsLua
1159 pub fn open_string(&self) {
1160 unsafe { ffi::luaopen_string(self.lua) }
1161 }
1162
1163 /// Opens table library.
1164 ///
1165 /// <https://www.lua.org/manual/5.2/manual.html#pdf-luaopen_table>
1166 #[inline]
1167 // TODO(gmoshkin): this method should be part of AsLua
1168 pub fn open_table(&self) {
1169 unsafe { ffi::luaopen_table(self.lua) }
1170 }
1171
1172 /// Executes some Lua code in the context.
1173 ///
1174 /// The code will have access to all the global variables you set with methods such as `set`.
1175 /// Every time you execute some code in the context, the code can modify these global variables.
1176 ///
1177 /// The template parameter of this function is the return type of the expression that is being
1178 /// evaluated.
1179 /// In order to avoid compilation error, you should call this function either by doing
1180 /// `lua.eval::<T>(...)` or `let result: T = lua.eval(...);` where `T` is the type of
1181 /// the expression.
1182 /// The function will return an error if the actual return type of the expression doesn't
1183 /// match the template parameter.
1184 ///
1185 /// The return type must implement the `LuaRead` trait. See
1186 /// [the documentation at the crate root](index.html#pushing-and-loading-values) for more
1187 /// information.
1188 ///
1189 /// # Examples
1190 ///
1191 /// ```no_run
1192 /// use tlua::Lua;
1193 /// let lua = Lua::new();
1194 ///
1195 /// let twelve: i32 = lua.eval("return 3 * 4;").unwrap();
1196 /// let sixty = lua.eval::<i32>("return 6 * 10;").unwrap();
1197 /// ```
1198 #[track_caller]
1199 #[inline(always)]
1200 // TODO(gmoshkin): this method should be part of AsLua
1201 pub fn eval<'lua, T>(&'lua self, code: &str) -> Result<T, LuaError>
1202 where
1203 T: LuaRead<PushGuard<LuaFunction<PushGuard<&'lua Self>>>>,
1204 {
1205 LuaFunction::load(self, code)?.into_call()
1206 }
1207
1208 /// Executes some Lua code in the context
1209 /// passing the arguments in place of `...`.
1210 ///
1211 /// ```no_run
1212 /// use tlua::Lua;
1213 /// let lua = Lua::new();
1214 /// let two: i32 = lua.eval_with("return 1 + ...", 1).unwrap();
1215 /// assert_eq!(two, 2);
1216 /// ```
1217 /// See also [`Lua::eval`]
1218 #[track_caller]
1219 #[inline(always)]
1220 // TODO(gmoshkin): this method should be part of AsLua
1221 pub fn eval_with<'lua, A, T>(&'lua self, code: &str, args: A) -> Result<T, CallError<A::Err>>
1222 where
1223 A: PushInto<LuaState>,
1224 T: LuaRead<PushGuard<LuaFunction<PushGuard<&'lua Self>>>>,
1225 {
1226 LuaFunction::load(self, code)?.into_call_with_args(args)
1227 }
1228
1229 /// Executes some Lua code in the context.
1230 ///
1231 /// The code will have access to all the global variables you set with
1232 /// methods such as `set`. Every time you execute some code in the context,
1233 /// the code can modify these global variables.
1234 ///
1235 /// # Examples
1236 ///
1237 /// ```no_run
1238 /// use tlua::Lua;
1239 /// let lua = Lua::new();
1240 /// lua.exec("function multiply_by_two(a) return a * 2 end").unwrap();
1241 /// lua.exec("twelve = multiply_by_two(6)").unwrap();
1242 /// ```
1243 #[track_caller]
1244 #[inline(always)]
1245 // TODO(gmoshkin): this method should be part of AsLua
1246 pub fn exec(&self, code: &str) -> Result<(), LuaError> {
1247 LuaFunction::load(self, code)?.into_call()
1248 }
1249
1250 /// Executes some Lua code in the context
1251 /// passing the arguments in place of `...`.
1252 ///
1253 /// # Examples
1254 ///
1255 /// ```no_run
1256 /// use tlua::Lua;
1257 /// let lua = Lua::new();
1258 /// lua.exec_with("a, b = ...; c = a * b", (3, 4)).unwrap();
1259 /// let c: i32 = lua.get("c").unwrap();
1260 /// assert_eq!(c, 12);
1261 /// ```
1262 /// See also [`Lua::exec`]
1263 #[track_caller]
1264 #[inline(always)]
1265 // TODO(gmoshkin): this method should be part of AsLua
1266 pub fn exec_with<A>(&self, code: &str, args: A) -> Result<(), CallError<A::Err>>
1267 where
1268 A: PushInto<LuaState>,
1269 {
1270 LuaFunction::load(self, code)?.into_call_with_args(args)
1271 }
1272
1273 /// Executes some Lua code on the context.
1274 ///
1275 /// This does the same thing as [the `eval` method](#method.eval), but the
1276 /// code to evaluate is loaded from an object that implements `Read`.
1277 ///
1278 /// Use this method when you potentially have a large amount of code (for example if you read
1279 /// the code from a file) in order to avoid having to put everything in memory first before
1280 /// passing it to the Lua interpreter.
1281 ///
1282 /// # Example
1283 ///
1284 /// ```no_run
1285 /// use std::fs::File;
1286 /// use tlua::Lua;
1287 ///
1288 /// let mut lua = Lua::new();
1289 /// let script = File::open("script.lua").unwrap();
1290 /// let res: u32 = lua.eval_from(script).unwrap();
1291 /// ```
1292 #[track_caller]
1293 #[inline(always)]
1294 // TODO(gmoshkin): this method should be part of AsLua
1295 pub fn eval_from<'lua, T>(&'lua self, code: impl Read) -> Result<T, LuaError>
1296 where
1297 T: LuaRead<PushGuard<LuaFunction<PushGuard<&'lua Self>>>>,
1298 {
1299 LuaFunction::load_from_reader(self, code)?.into_call()
1300 }
1301
1302 /// Executes some Lua code on the context.
1303 ///
1304 /// This does the same thing as [the `exec` method](#method.exec), but the
1305 /// code to execute is loaded from an object that implements `Read`.
1306 ///
1307 /// Use this method when you potentially have a large amount of code (for
1308 /// example if you read the code from a file) in order to avoid having to
1309 /// put everything in memory first before passing it to the Lua interpreter.
1310 ///
1311 /// # Example
1312 ///
1313 /// ```no_run
1314 /// use std::fs::File;
1315 /// use tlua::Lua;
1316 ///
1317 /// let mut lua = Lua::new();
1318 /// let script = File::open("script.lua").unwrap();
1319 /// lua.exec_from(script).unwrap();
1320 /// ```
1321 #[track_caller]
1322 #[inline(always)]
1323 // TODO(gmoshkin): this method should be part of AsLua
1324 pub fn exec_from(&self, code: impl Read) -> Result<(), LuaError> {
1325 LuaFunction::load_from_reader(self, code)?.into_call()
1326 }
1327
1328 /// Reads the value of a global variable.
1329 ///
1330 /// Returns `None` if the variable doesn't exist or has the wrong type.
1331 ///
1332 /// The type must implement the `LuaRead` trait. See
1333 /// [the documentation at the crate root](index.html#pushing-and-loading-values) for more
1334 /// information.
1335 ///
1336 /// # Example
1337 ///
1338 /// ```no_run
1339 /// use tlua::Lua;
1340 /// let lua = Lua::new();
1341 /// lua.exec("a = 5").unwrap();
1342 /// let a: i32 = lua.get("a").unwrap();
1343 /// assert_eq!(a, 5);
1344 /// ```
1345 #[inline]
1346 // TODO(gmoshkin): this method should be part of AsLua
1347 pub fn get<'lua, V, I>(&'lua self, index: I) -> Option<V>
1348 where
1349 I: Borrow<str>,
1350 V: LuaRead<PushGuard<&'lua Self>>,
1351 {
1352 let index = CString::new(index.borrow()).unwrap();
1353 unsafe {
1354 ffi::lua_getglobal(self.lua, index.as_ptr());
1355 V::lua_read(PushGuard::new(self, 1)).ok()
1356 }
1357 }
1358
1359 /// Reads the value of a global, capturing the context by value.
1360 #[inline]
1361 // TODO(gmoshkin): this method should be part of AsLua
1362 pub fn into_get<V, I>(self, index: I) -> Result<V, PushGuard<Self>>
1363 where
1364 I: Borrow<str>,
1365 V: LuaRead<PushGuard<Self>>,
1366 {
1367 let index = CString::new(index.borrow()).unwrap();
1368 unsafe {
1369 ffi::lua_getglobal(self.lua, index.as_ptr());
1370 V::lua_read(PushGuard::new(self, 1)).map_err(|(l, _)| l)
1371 }
1372 }
1373
1374 /// Modifies the value of a global variable.
1375 ///
1376 /// If you want to write an array, you are encouraged to use
1377 /// [the `empty_array` method](#method.empty_array) instead.
1378 ///
1379 /// The type must implement the `PushOne` trait. See
1380 /// [the documentation at the crate root](index.html#pushing-and-loading-values) for more
1381 /// information.
1382 ///
1383 /// # Example
1384 ///
1385 /// ```no_run
1386 /// use tlua::Lua;
1387 /// let lua = Lua::new();
1388 ///
1389 /// lua.set("a", 12);
1390 /// let six: i32 = lua.eval("return a / 2;").unwrap();
1391 /// assert_eq!(six, 6);
1392 /// ```
1393 #[inline]
1394 // TODO(gmoshkin): this method should be part of AsLua
1395 pub fn set<'lua, I, V>(&'lua self, index: I, value: V)
1396 where
1397 I: Borrow<str>,
1398 V: PushOneInto<&'lua Self>,
1399 <V as PushInto<&'lua Self>>::Err: Into<Void>,
1400 {
1401 match self.checked_set(index, value) {
1402 Ok(_) => (),
1403 Err(_) => unreachable!(),
1404 }
1405 }
1406
1407 /// Modifies the value of a global variable.
1408 // TODO: docs
1409 #[inline]
1410 // TODO(gmoshkin): this method should be part of AsLua
1411 pub fn checked_set<'lua, I, V>(
1412 &'lua self,
1413 index: I,
1414 value: V,
1415 ) -> Result<(), <V as PushInto<&'lua Self>>::Err>
1416 where
1417 I: Borrow<str>,
1418 V: PushOneInto<&'lua Self>,
1419 {
1420 unsafe {
1421 ffi::lua_pushglobaltable(self.lua);
1422 self.as_lua().push(index.borrow()).assert_one_and_forget();
1423 match self.try_push(value) {
1424 Ok(pushed) => {
1425 assert_eq!(pushed.size, 1);
1426 pushed.forget()
1427 }
1428 Err((err, lua)) => {
1429 ffi::lua_pop(lua.as_lua(), 2);
1430 return Err(err);
1431 }
1432 };
1433 ffi::lua_settable(self.lua, -3);
1434 ffi::lua_pop(self.lua, 1);
1435 Ok(())
1436 }
1437 }
1438
1439 /// Sets the value of a global variable to an empty array, then loads it.
1440 ///
1441 /// This is the function you should use if you want to set the value of a global variable to
1442 /// an array. After calling it, you will obtain a `LuaTable` object which you can then fill
1443 /// with the elements of the array.
1444 ///
1445 /// # Example
1446 ///
1447 /// ```no_run
1448 /// use tlua::Lua;
1449 /// let lua = Lua::new();
1450 /// lua.openlibs(); // Necessary for `ipairs`.
1451 ///
1452 /// {
1453 /// let mut array = lua.empty_array("my_values");
1454 /// array.set(1, 10); // Don't forget that Lua arrays are indexed from 1.
1455 /// array.set(2, 15);
1456 /// array.set(3, 20);
1457 /// }
1458 ///
1459 /// let sum: i32 = lua.eval(r#"
1460 /// local sum = 0
1461 /// for i, val in ipairs(my_values) do
1462 /// sum = sum + val
1463 /// end
1464 /// return sum
1465 /// "#).unwrap();
1466 ///
1467 /// assert_eq!(sum, 45);
1468 /// ```
1469 #[inline]
1470 // TODO(gmoshkin): this method should be part of AsLua
1471 pub fn empty_array<I>(&self, index: I) -> LuaTable<PushGuard<&Self>>
1472 where
1473 I: Borrow<str>,
1474 {
1475 unsafe {
1476 ffi::lua_pushglobaltable(self.as_lua());
1477 match index.borrow().push_to_lua(self.as_lua()) {
1478 Ok(pushed) => pushed.forget(),
1479 Err(_) => unreachable!(),
1480 };
1481 ffi::lua_newtable(self.as_lua());
1482 ffi::lua_settable(self.as_lua(), -3);
1483 ffi::lua_pop(self.as_lua(), 1);
1484
1485 // TODO: cleaner implementation
1486 self.get(index).unwrap()
1487 }
1488 }
1489
1490 /// Loads the array containing the global variables.
1491 ///
1492 /// In lua, the global variables accessible from the lua code are all part of a table which
1493 /// you can load here.
1494 ///
1495 /// # Examples
1496 ///
1497 /// The function can be used to write global variables, just like `set`.
1498 ///
1499 /// ```no_run
1500 /// use tlua::Lua;
1501 /// let lua = Lua::new();
1502 /// lua.globals_table().set("a", 5);
1503 /// assert_eq!(lua.get::<i32, _>("a"), Some(5));
1504 /// ```
1505 ///
1506 /// A more useful feature for this function is that it allows you to set the metatable of the
1507 /// global variables. See TODO for more info.
1508 ///
1509 /// ```no_run
1510 /// use tlua::Lua;
1511 /// use tlua::AnyLuaValue;
1512 ///
1513 /// let lua = Lua::new();
1514 /// {
1515 /// let globals = lua.globals_table();
1516 /// let metatable = globals.get_or_create_metatable();
1517 /// metatable.set("__index", tlua::function2(|_: AnyLuaValue, var: String| -> AnyLuaValue {
1518 /// println!("The user tried to access the variable {:?}", var);
1519 /// AnyLuaValue::LuaNumber(48.0)
1520 /// }));
1521 /// }
1522 ///
1523 /// let b: i32 = lua.eval("return b * 2;").unwrap();
1524 /// // -> The user tried to access the variable "b"
1525 ///
1526 /// assert_eq!(b, 96);
1527 /// ```
1528 #[inline]
1529 // TODO(gmoshkin): this method should be part of AsLua
1530 pub fn globals_table(&self) -> LuaTable<PushGuard<&Self>> {
1531 unsafe {
1532 ffi::lua_pushglobaltable(self.lua);
1533 let guard = PushGuard::new(self, 1);
1534 LuaRead::lua_read(guard).ok().unwrap()
1535 }
1536 }
1537}
1538
1539impl Default for TempLua {
1540 fn default() -> Self {
1541 Self::new()
1542 }
1543}
1544
1545impl<T> Drop for Lua<T>
1546where
1547 T: on_drop::OnDrop,
1548{
1549 #[inline]
1550 fn drop(&mut self) {
1551 self.on_drop.on_drop(self.lua)
1552 }
1553}
1554
1555impl<L: AsLua> Drop for PushGuard<L> {
1556 #[inline]
1557 fn drop(&mut self) {
1558 if self.size != 0 {
1559 unsafe {
1560 ffi::lua_pop(self.lua.as_lua(), self.size as _);
1561 }
1562 }
1563 }
1564}
1565
1566#[derive(Debug, Clone, Copy)]
1567pub struct AbsoluteIndex(NonZeroI32);
1568
1569impl AbsoluteIndex {
1570 /// Convert the non-zero index into an absolute index.
1571 ///
1572 /// # Panicking
1573 /// Will panic if `index` equals to `-1 - lua_gettop(lua)`.
1574 #[inline]
1575 #[track_caller]
1576 pub fn new<L>(index: NonZeroI32, lua: L) -> Self
1577 where
1578 L: AsLua,
1579 {
1580 Self::try_new(index, lua).expect("Invalid relative index")
1581 }
1582
1583 /// Convert the non-zero `index` into an absolute index or return `None` if
1584 /// the result would not be non-zero.
1585 #[inline]
1586 pub fn try_new<L>(index: impl Into<i32>, lua: L) -> Option<Self>
1587 where
1588 L: AsLua,
1589 {
1590 let top = unsafe { ffi::lua_gettop(lua.as_lua()) };
1591 let index = index.into();
1592 if ffi::is_relative_index(index) {
1593 NonZeroI32::new(top + index + 1).map(Self)
1594 } else {
1595 NonZeroI32::new(index).map(Self)
1596 }
1597 }
1598
1599 /// # Safety
1600 /// `index` must be a valid absolute or relative index into the lua stack
1601 /// with which it's going to be used
1602 pub unsafe fn new_unchecked(index: NonZeroI32) -> Self {
1603 Self(index)
1604 }
1605
1606 pub fn get(&self) -> u32 {
1607 self.0.get() as _
1608 }
1609}
1610
1611impl From<AbsoluteIndex> for i32 {
1612 fn from(index: AbsoluteIndex) -> i32 {
1613 index.0.get()
1614 }
1615}