ezlua/
luaapi.rs

1use crate::{
2    convert::{Index, ToLua},
3    error::Error,
4    ffi::*,
5    state::State,
6    str::*,
7};
8
9use alloc::borrow::Cow;
10use alloc::string::String;
11use alloc::vec::Vec;
12use core::ffi::{c_char, c_int, c_void};
13use core::{mem, ptr, slice, str};
14
15#[allow(non_camel_case_types)]
16type size_t = usize;
17
18#[extend::ext(pub, name = UnsafeLuaApi)]
19impl State {
20    /// Initializes a new Lua state. This function does not open any libraries
21    /// by default. Calls `lua_newstate` internally.
22    fn new() -> *mut lua_State {
23        unsafe { luaL_newstate() }
24    }
25
26    /// Returns an unsafe pointer to the wrapped `lua_State`.
27    #[inline(always)]
28    fn as_ptr(&self) -> *mut lua_State {
29        self.state
30    }
31
32    /// Maps to `luaL_openlibs`.
33    fn open_libs(&self) {
34        unsafe {
35            luaL_openlibs(self.state);
36        }
37    }
38
39    /// Maps to `luaopen_base`.
40    #[inline(always)]
41    fn open_base(&self) -> c_int {
42        unsafe { luaopen_base(self.state) }
43    }
44
45    /// Maps to `luaopen_coroutine`.
46    #[inline(always)]
47    fn open_coroutine(&self) -> c_int {
48        unsafe { luaopen_coroutine(self.state) }
49    }
50
51    /// Maps to `luaopen_table`.
52    #[inline(always)]
53    fn open_table(&self) -> c_int {
54        unsafe { luaopen_table(self.state) }
55    }
56
57    /// Maps to `luaopen_io`.
58    #[inline(always)]
59    fn open_io(&self) -> c_int {
60        unsafe { luaopen_io(self.state) }
61    }
62
63    /// Maps to `luaopen_os`.
64    #[inline(always)]
65    fn open_os(&self) -> c_int {
66        unsafe { luaopen_os(self.state) }
67    }
68
69    /// Maps to `luaopen_string`.
70    #[inline(always)]
71    fn open_string(&self) -> c_int {
72        unsafe { luaopen_string(self.state) }
73    }
74
75    /// Maps to `luaopen_utf8`.
76    #[inline(always)]
77    fn open_utf8(&self) -> c_int {
78        unsafe { luaopen_utf8(self.state) }
79    }
80
81    /// Maps to `luaopen_math`.
82    #[inline(always)]
83    fn open_math(&self) -> c_int {
84        unsafe { luaopen_math(self.state) }
85    }
86
87    /// Maps to `luaopen_debug`.
88    #[inline(always)]
89    fn open_debug(&self) -> c_int {
90        unsafe { luaopen_debug(self.state) }
91    }
92
93    /// Maps to `luaopen_package`.
94    #[inline(always)]
95    fn open_package(&self) -> c_int {
96        unsafe { luaopen_package(self.state) }
97    }
98
99    /// Maps to `luaL_dofile`.
100    fn do_file(&self, filename: &str) -> i32 {
101        let c_str = CString::new(filename).unwrap();
102        unsafe { luaL_dofile(self.state, c_str.as_ptr()) }
103    }
104
105    /// Maps to `luaL_dostring`.
106    fn do_string(&self, s: &str) -> i32 {
107        let c_str = CString::new(s).unwrap();
108        unsafe { luaL_dostring(self.state, c_str.as_ptr()) }
109    }
110
111    //===========================================================================
112    // State manipulation
113    //===========================================================================
114    /// Maps to `lua_close`.
115    #[inline(always)]
116    fn close(&self) {
117        unsafe {
118            lua_close(self.state);
119        }
120    }
121
122    /// [-0, +1, m] Maps to `lua_newthread`.
123    #[inline(always)]
124    fn new_thread(&self) -> *mut lua_State {
125        unsafe { lua_newthread(self.state) }
126    }
127
128    /// Maps to `lua_atpanic`.
129    #[inline(always)]
130    fn at_panic(&self, panicf: lua_CFunction) -> lua_CFunction {
131        unsafe { lua_atpanic(self.state, panicf) }
132    }
133
134    /// Maps to `lua_version`.
135    fn version(state: *mut lua_State) -> lua_Number {
136        unsafe { lua_version(state) }
137    }
138
139    //===========================================================================
140    // Basic stack manipulation
141    //===========================================================================
142    /// Maps to `lua_absindex`.
143    #[inline(always)]
144    fn abs_index(&self, idx: Index) -> Index {
145        unsafe { lua_absindex(self.state, idx) }
146    }
147
148    /// Maps to `lua_gettop`.
149    #[inline(always)]
150    fn get_top(&self) -> Index {
151        unsafe { lua_gettop(self.state) }
152    }
153
154    /// Maps to `lua_settop`.
155    #[inline(always)]
156    fn set_top(&self, index: Index) {
157        unsafe { lua_settop(self.state, index) }
158    }
159
160    /// Maps to `lua_rotate`.
161    #[inline(always)]
162    fn rotate(&self, idx: Index, n: c_int) {
163        unsafe { lua_rotate(self.state, idx, n) }
164    }
165
166    /// Maps to `lua_copy`.
167    #[inline(always)]
168    fn copy(&self, from_idx: Index, to_idx: Index) {
169        unsafe { lua_copy(self.state, from_idx, to_idx) }
170    }
171
172    /// Maps to `lua_checkstack`.
173    #[inline(always)]
174    fn check_stack(&self, extra: c_int) -> bool {
175        let result = unsafe { lua_checkstack(self.state, extra) };
176        result != 0
177    }
178
179    /// Maps to `lua_xmove`.
180    #[inline(always)]
181    fn xmove(&self, to: *mut lua_State, n: c_int) {
182        unsafe { lua_xmove(self.state, to, n) }
183    }
184
185    //===========================================================================
186    // Access functions (stack -> C)
187    //===========================================================================
188    /// Maps to `lua_isnumber`.
189    #[inline(always)]
190    fn is_number(&self, index: Index) -> bool {
191        unsafe { lua_isnumber(self.state, index) == 1 }
192    }
193
194    /// Maps to `lua_isstring`.
195    #[inline(always)]
196    fn is_string(&self, index: Index) -> bool {
197        unsafe { lua_isstring(self.state, index) == 1 }
198    }
199
200    /// Maps to `lua_iscfunction`.
201    #[inline(always)]
202    fn is_native_fn(&self, index: Index) -> bool {
203        unsafe { lua_iscfunction(self.state, index) == 1 }
204    }
205
206    /// Maps to `lua_isinteger`.
207    #[inline(always)]
208    fn is_integer(&self, index: Index) -> bool {
209        unsafe { lua_isinteger(self.state, index) == 1 }
210    }
211
212    /// Maps to `lua_isuserdata`.
213    #[inline(always)]
214    fn is_userdata(&self, index: Index) -> bool {
215        unsafe { lua_isuserdata(self.state, index) == 1 }
216    }
217
218    /// Maps to `lua_type`.
219    #[inline(always)]
220    fn type_of(&self, index: Index) -> Type {
221        let result = unsafe { lua_type(self.state, index) };
222        Type::from_c_int(result)
223    }
224
225    /// Maps to `lua_typename`.
226    #[inline(always)]
227    fn typename_of(&self, tp: Type) -> Cow<str> {
228        unsafe {
229            let ptr = lua_typename(self.state, tp as c_int);
230            let slice = CStr::from_ptr(ptr).to_bytes();
231            String::from_utf8_lossy(slice)
232        }
233    }
234
235    /// Maps to `lua_toboolean`.
236    #[inline(always)]
237    fn to_bool(&self, index: Index) -> bool {
238        let result = unsafe { lua_toboolean(self.state, index) };
239        result != 0
240    }
241
242    // omitted: lua_tolstring
243
244    /// Maps to `lua_rawlen`.
245    #[inline(always)]
246    fn raw_len(&self, index: Index) -> size_t {
247        unsafe { lua_rawlen(self.state, index) as _ }
248    }
249
250    /// Maps to `lua_tocfunction`.
251    #[inline(always)]
252    fn to_native_fn(&self, index: Index) -> lua_CFunction {
253        let result = unsafe { lua_tocfunction(self.state, index) };
254        result
255    }
256
257    /// Maps to `lua_touserdata`.
258    #[inline(always)]
259    fn to_userdata(&self, index: Index) -> *mut c_void {
260        unsafe { lua_touserdata(self.state, index) }
261    }
262
263    /// Maps to `lua_tothread`.
264    #[inline]
265    fn to_thread(&self, index: Index) -> Option<&mut lua_State> {
266        unsafe { lua_tothread(self.state, index).as_mut() }
267    }
268
269    /// Maps to `lua_topointer`.
270    #[inline(always)]
271    fn to_pointer(&self, index: Index) -> *const c_void {
272        unsafe { lua_topointer(self.state, index) }
273    }
274
275    //===========================================================================
276    // Comparison and arithmetic functions
277    //===========================================================================
278    /// Maps to `lua_arith`.
279    #[inline(always)]
280    fn arith(&self, op: Arithmetic) {
281        unsafe { lua_arith(self.state, op as c_int) }
282    }
283
284    /// Maps to `lua_rawequal`.
285    #[inline(always)]
286    fn raw_equal(&self, idx1: Index, idx2: Index) -> bool {
287        let result = unsafe { lua_rawequal(self.state, idx1, idx2) };
288        result != 0
289    }
290
291    /// Maps to `lua_compare`.
292    #[inline(always)]
293    fn compare(&self, idx1: Index, idx2: Index, op: Comparison) -> bool {
294        let result = unsafe { lua_compare(self.state, idx1, idx2, op as c_int) };
295        result != 0
296    }
297
298    //===========================================================================
299    // Push functions (C -> stack)
300    //===========================================================================
301    /// Maps to `lua_pushnil`.
302    #[inline(always)]
303    fn push_nil(&self) {
304        unsafe { lua_pushnil(self.state) }
305    }
306
307    /// Maps to `lua_pushnumber`.
308    #[inline(always)]
309    fn push_number(&self, n: lua_Number) {
310        unsafe { lua_pushnumber(self.state, n) }
311    }
312
313    /// Maps to `lua_pushinteger`.
314    #[inline(always)]
315    fn push_integer(&self, i: lua_Integer) {
316        unsafe { lua_pushinteger(self.state, i) }
317    }
318
319    // omitted: lua_pushstring
320
321    /// Maps to `lua_pushlstring`.
322    #[inline(always)]
323    fn push_string(&self, s: &str) {
324        unsafe { lua_pushlstring(self.state, s.as_ptr() as *const _, s.len() as size_t) };
325    }
326
327    /// Maps to `lua_pushlstring`.
328    #[inline(always)]
329    fn push_bytes(&self, s: &[u8]) {
330        unsafe { lua_pushlstring(self.state, s.as_ptr() as *const _, s.len() as size_t) };
331    }
332
333    // omitted: lua_pushvfstring
334    // omitted: lua_pushfstring
335
336    /// Maps to `lua_pushcclosure`.
337    #[inline(always)]
338    fn push_cclosure(&self, f: lua_CFunction, n: c_int) {
339        unsafe { lua_pushcclosure(self.state, f, n) }
340    }
341
342    /// Maps to `lua_pushboolean`.
343    #[inline(always)]
344    fn push_bool(&self, b: bool) {
345        unsafe { lua_pushboolean(self.state, b as c_int) }
346    }
347
348    /// Maps to `lua_pushlightuserdata`. The Lua state will receive a pointer to
349    /// the given value. The caller is responsible for cleaning up the data. Any
350    /// code that manipulates the userdata is free to modify its contents, so
351    /// memory safety is not guaranteed.
352    #[inline(always)]
353    fn push_light_userdata<T>(&self, ud: *mut T) {
354        unsafe { lua_pushlightuserdata(self.state, mem::transmute(ud)) }
355    }
356
357    /// Maps to `lua_pushthread`.
358    #[inline(always)]
359    fn push_thread(&self) -> bool {
360        let result = unsafe { lua_pushthread(self.state) };
361        result != 1
362    }
363
364    /// Maps to `lua_pushvalue`.
365    #[inline(always)]
366    fn push_value(&self, index: Index) {
367        unsafe { lua_pushvalue(self.state, index) }
368    }
369
370    //===========================================================================
371    // Get functions (Lua -> stack)
372    //===========================================================================
373    /// [-0, +1, -] `lua_getglobal`.
374    #[inline(always)]
375    fn get_global(&self, name: &CStr) -> Type {
376        Type::from_c_int(unsafe { lua_getglobal(self.state, name.as_ptr()) })
377    }
378
379    /// Maps to `lua_gettable`.
380    #[inline(always)]
381    fn get_table(&self, index: Index) -> Type {
382        let ty = unsafe { lua_gettable(self.state, index) };
383        Type::from_c_int(ty)
384    }
385
386    /// Maps to `lua_getfield`.
387    #[inline(always)]
388    fn get_field(&self, index: Index, k: &CStr) -> Type {
389        Type::from_c_int(unsafe { lua_getfield(self.state, index, k.as_ptr()) })
390    }
391
392    /// Maps to `lua_geti`.
393    #[inline(always)]
394    fn geti(&self, index: Index, i: lua_Integer) -> Type {
395        let ty = unsafe { lua_geti(self.state, index, i) };
396        Type::from_c_int(ty)
397    }
398
399    /// [-1, +1, -] `lua_rawget`.
400    #[inline(always)]
401    fn raw_get(&self, index: Index) -> Type {
402        let ty = unsafe { lua_rawget(self.state, index) };
403        Type::from_c_int(ty)
404    }
405
406    /// Maps to `lua_rawgeti`.
407    #[inline(always)]
408    fn raw_geti(&self, index: Index, n: lua_Integer) -> Type {
409        let ty = unsafe { lua_rawgeti(self.state, index, n) };
410        Type::from_c_int(ty)
411    }
412
413    /// [0, +1, -] `lua_rawgetp`.
414    #[inline(always)]
415    fn raw_getp<T>(&self, index: Index, p: *const T) -> Type {
416        let ty = unsafe { lua_rawgetp(self.state, index, mem::transmute(p)) };
417        Type::from_c_int(ty)
418    }
419
420    /// Maps to `lua_createtable`.
421    #[inline(always)]
422    fn create_table(&self, narr: c_int, nrec: c_int) {
423        unsafe { lua_createtable(self.state, narr, nrec) }
424    }
425
426    /// Maps to `lua_newuserdata`. The pointer returned is owned by the Lua state
427    /// and it will be garbage collected when it is no longer in use or the state
428    /// is closed. To specify custom cleanup behavior, use a `__gc` metamethod.
429    #[inline(always)]
430    fn new_userdata(&self, sz: size_t) -> *mut c_void {
431        unsafe { lua_newuserdata(self.state, sz) }
432    }
433
434    #[inline(always)]
435    fn new_userdatauv(&self, sz: size_t, n: i32) -> *mut c_void {
436        unsafe { lua_newuserdatauv(self.state, sz, n) }
437    }
438
439    /// [-0, +(0|1), –] `lua_getmetatable`.
440    #[inline(always)]
441    fn get_metatable(&self, objindex: Index) -> bool {
442        let result = unsafe { lua_getmetatable(self.state, objindex) };
443        result != 0
444    }
445
446    /// Maps to `lua_getuservalue`.
447    #[inline(always)]
448    fn get_uservalue(&self, idx: Index) -> Type {
449        let result = unsafe { lua_getuservalue(self.state, idx) };
450        Type::from_c_int(result)
451    }
452
453    /// [-0, +1, –] Maps to `lua_getiuservalue`.
454    #[inline(always)]
455    fn get_iuservalue(&self, idx: Index, n: i32) -> Type {
456        let result = unsafe { lua_getiuservalue(self.state, idx, n) };
457        Type::from_c_int(result)
458    }
459
460    //===========================================================================
461    // Set functions (stack -> Lua)
462    //===========================================================================
463    /// Maps to `lua_setglobal`.
464    #[inline(always)]
465    fn set_global(&self, var: &CStr) {
466        unsafe { lua_setglobal(self.state, var.as_ptr()) }
467    }
468
469    /// Maps to `lua_settable`.
470    #[inline(always)]
471    fn set_table(&self, idx: Index) {
472        unsafe { lua_settable(self.state, idx) }
473    }
474
475    /// Maps to `lua_setfield`.
476    #[inline(always)]
477    fn set_field(&self, idx: Index, k: &CStr) {
478        unsafe { lua_setfield(self.state, idx, k.as_ptr()) }
479    }
480
481    /// Maps to `lua_seti`.
482    #[inline(always)]
483    fn seti(&self, idx: Index, n: lua_Integer) {
484        unsafe { lua_seti(self.state, idx, n) }
485    }
486
487    /// [-2, +0, m] `lua_rawset`.
488    #[inline(always)]
489    fn raw_set(&self, idx: Index) {
490        unsafe { lua_rawset(self.state, idx) }
491    }
492
493    /// Maps to `lua_rawseti`.
494    #[inline(always)]
495    fn raw_seti(&self, idx: Index, n: lua_Integer) {
496        unsafe { lua_rawseti(self.state, idx, n) }
497    }
498
499    /// Maps to `lua_rawsetp`.
500    #[inline(always)]
501    fn raw_setp<T>(&self, idx: Index, p: *const T) {
502        unsafe { lua_rawsetp(self.state, idx, mem::transmute(p)) }
503    }
504
505    /// [-1, +0, -] `lua_setmetatable`.
506    #[inline(always)]
507    fn set_metatable(&self, objindex: Index) {
508        unsafe { lua_setmetatable(self.state, objindex) };
509    }
510
511    /// [-1, +0, -] `lua_setuservalue`.
512    #[inline(always)]
513    fn set_uservalue(&self, idx: Index) {
514        unsafe {
515            lua_setuservalue(self.state, idx);
516        }
517    }
518
519    /// [-1, +0, -] Maps to `lua_setiuservalue`.
520    #[inline(always)]
521    fn set_iuservalue(&self, idx: Index, n: i32) {
522        unsafe {
523            lua_setiuservalue(self.state, idx, n);
524        }
525    }
526
527    /// Maps to `luaL_callmeta`.
528    #[inline(always)]
529    fn call(&self, n: c_int, r: c_int) {
530        unsafe { lua_call(self.state, n, r) }
531    }
532
533    fn tailcall(self, n: c_int, r: c_int) {
534        let state = self.state;
535        drop(self);
536        unsafe { lua_call(state, n, r) }
537    }
538
539    //===========================================================================
540    // Coroutine functions
541    //===========================================================================
542    /// Maps to `lua_resume`.
543    fn resume(&self, from: *mut lua_State, nargs: c_int, nresults: &mut c_int) -> ThreadStatus {
544        let result = unsafe { lua_resume(self.state, from, nargs, nresults) };
545        ThreadStatus::from_c_int(result)
546    }
547
548    /// Maps to `lua_status`.
549    #[inline(always)]
550    fn status(&self) -> ThreadStatus {
551        let result = unsafe { lua_status(self.state) };
552        ThreadStatus::from_c_int(result)
553    }
554
555    /// Maps to `lua_isyieldable`.
556    #[inline(always)]
557    fn is_yieldable(&self) -> bool {
558        let result = unsafe { lua_isyieldable(self.state) };
559        result != 0
560    }
561
562    //===========================================================================
563    // Garbage-collection function
564    //===========================================================================
565    // TODO: return typing?
566    /// Maps to `lua_gc`.
567    #[inline(always)]
568    fn gc(&self, what: GcOption, data: c_int) -> c_int {
569        unsafe { lua_gc(self.state, what as c_int, data) }
570    }
571
572    //===========================================================================
573    // Miscellaneous functions
574    //===========================================================================
575    /// Maps to `lua_error`.
576    #[inline(always)]
577    fn error(self) -> ! {
578        let state = self.state;
579        drop(self);
580        unsafe { lua_error(state) };
581    }
582
583    /// Maps to `lua_next`.
584    #[inline(always)]
585    fn next(&self, idx: Index) -> bool {
586        let result = unsafe { lua_next(self.state, idx) };
587        result != 0
588    }
589
590    /// Maps to `lua_concat`.
591    #[inline(always)]
592    fn concat(&self, n: c_int) {
593        unsafe { lua_concat(self.state, n) }
594    }
595
596    /// Maps to `lua_len`.
597    #[inline(always)]
598    fn len(&self, idx: Index) {
599        unsafe { lua_len(self.state, idx) }
600    }
601
602    /// Maps to `lua_stringtonumber`.
603    fn string_to_number(&self, s: &str) -> size_t {
604        let c_str = CString::new(s).unwrap();
605        unsafe { lua_stringtonumber(self.state, c_str.as_ptr()) }
606    }
607
608    /// Maps to `lua_getallocf`.
609    #[inline(always)]
610    fn get_alloc_fn(&self) -> (lua_Alloc, *mut c_void) {
611        let mut slot = ptr::null_mut();
612        (unsafe { lua_getallocf(self.state, &mut slot) }, slot)
613    }
614
615    /// Maps to `lua_setallocf`.
616    #[inline(always)]
617    fn set_alloc_fn(&self, f: lua_Alloc, ud: *mut c_void) {
618        unsafe { lua_setallocf(self.state, f, ud) }
619    }
620
621    /// Maps to `lua_tonumber`.
622    #[inline(always)]
623    fn to_number(&self, index: Index) -> lua_Number {
624        unsafe { lua_tonumber(self.state, index) }
625    }
626
627    /// Maps to `lua_tonumberx`.
628    #[inline(always)]
629    fn to_numberx(&self, index: Index) -> Option<lua_Number> {
630        let mut suc = 0i32;
631        let r = unsafe { lua_tonumberx(self.state, index, &mut suc) };
632        if suc > 0 {
633            Some(r)
634        } else {
635            None
636        }
637    }
638
639    /// Maps to `lua_tointeger`.
640    #[inline(always)]
641    fn to_integer(&self, index: Index) -> lua_Integer {
642        unsafe { lua_tointeger(self.state, index) }
643    }
644
645    /// Maps to `lua_tointegerx`.
646    #[inline(always)]
647    fn to_integerx(&self, index: Index) -> Option<lua_Integer> {
648        let mut isnum: c_int = 0;
649        let r = unsafe { lua_tointegerx(self.state, index, &mut isnum) };
650        if isnum == 0 {
651            None
652        } else {
653            Some(r)
654        }
655    }
656
657    /// Maps to `lua_pop`.
658    #[inline(always)]
659    fn pop(&self, n: c_int) {
660        unsafe { lua_pop(self.state, n) }
661    }
662
663    /// Maps to `lua_newtable`.
664    #[inline(always)]
665    fn new_table(&self) {
666        unsafe { lua_newtable(self.state) }
667    }
668
669    /// Maps to `lua_register`.
670    #[inline(always)]
671    fn register(&self, n: &str, f: CFunction) {
672        let c_str = CString::new(n).unwrap();
673        unsafe { lua_register(self.state, c_str.as_ptr(), Some(f)) }
674    }
675
676    /// Maps to `lua_pushcfunction`.
677    #[inline(always)]
678    fn push_fn(&self, f: lua_CFunction) {
679        unsafe { lua_pushcfunction(self.state, f) }
680    }
681
682    /// Maps to `lua_isfunction`.
683    #[inline(always)]
684    fn is_function(&self, index: Index) -> bool {
685        unsafe { lua_isfunction(self.state, index) == 1 }
686    }
687
688    /// Maps to `lua_istable`.
689    #[inline(always)]
690    fn is_table(&self, index: Index) -> bool {
691        unsafe { lua_istable(self.state, index) == 1 }
692    }
693
694    /// Maps to `lua_islightuserdata`.
695    #[inline(always)]
696    fn is_light_userdata(&self, index: Index) -> bool {
697        unsafe { lua_islightuserdata(self.state, index) == 1 }
698    }
699
700    /// Maps to `lua_isnil`.
701    #[inline(always)]
702    fn is_nil(&self, index: Index) -> bool {
703        unsafe { lua_isnil(self.state, index) == 1 }
704    }
705
706    /// Maps to `lua_isboolean`.
707    #[inline(always)]
708    fn is_bool(&self, index: Index) -> bool {
709        unsafe { lua_isboolean(self.state, index) == 1 }
710    }
711
712    /// Maps to `lua_isthread`.
713    #[inline(always)]
714    fn is_thread(&self, index: Index) -> bool {
715        unsafe { lua_isthread(self.state, index) == 1 }
716    }
717
718    /// Maps to `lua_isnone`.
719    #[inline(always)]
720    fn is_none(&self, index: Index) -> bool {
721        unsafe { lua_isnone(self.state, index) == 1 }
722    }
723
724    /// Maps to `lua_isnoneornil`.
725    #[inline(always)]
726    fn is_none_or_nil(&self, index: Index) -> bool {
727        unsafe { lua_isnoneornil(self.state, index) == 1 }
728    }
729
730    // omitted: lua_pushliteral
731
732    /// Maps to `lua_pushglobaltable`.
733    #[inline(always)]
734    fn push_global_table(&self) {
735        unsafe { lua_pushglobaltable(self.state) };
736    }
737
738    /// Maps to `lua_insert`.
739    #[inline(always)]
740    fn insert(&self, idx: Index) {
741        unsafe { lua_insert(self.state, idx) }
742    }
743
744    /// Maps to `lua_remove`.
745    #[inline(always)]
746    fn remove(&self, idx: Index) {
747        unsafe { lua_remove(self.state, idx) }
748    }
749
750    /// Maps to `lua_replace`.
751    #[inline(always)]
752    fn replace(&self, idx: Index) {
753        unsafe { lua_replace(self.state, idx) }
754    }
755
756    //===========================================================================
757    // Debug API
758    //===========================================================================
759    /// Maps to `lua_getstack`.
760    fn get_stack(&self, level: c_int) -> Option<lua_Debug> {
761        let mut ar: lua_Debug = unsafe { core::mem::zeroed() };
762        let result = unsafe { lua_getstack(self.state, level, &mut ar) };
763        if result == 1 {
764            Some(ar)
765        } else {
766            None
767        }
768    }
769
770    /// Maps to `lua_getinfo`.
771    fn get_info(&self, what: &CStr, ar: &mut lua_Debug) -> i32 {
772        unsafe { lua_getinfo(self.state, what.as_ptr(), ar) }
773    }
774
775    /// Maps to `lua_getlocal`.
776    fn get_local(&self, ar: &lua_Debug, n: c_int) -> Option<&str> {
777        let ptr = unsafe { lua_getlocal(self.state, ar, n) };
778        if ptr.is_null() {
779            None
780        } else {
781            let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
782            str::from_utf8(slice).ok()
783        }
784    }
785
786    /// Maps to `lua_setlocal`.
787    fn set_local(&self, ar: &lua_Debug, n: c_int) -> Option<&str> {
788        let ptr = unsafe { lua_setlocal(self.state, ar, n) };
789        if ptr.is_null() {
790            None
791        } else {
792            let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
793            str::from_utf8(slice).ok()
794        }
795    }
796
797    /// Maps to `lua_getupvalue`.
798    fn get_upvalue(&self, funcindex: Index, n: c_int) -> Option<&str> {
799        let ptr = unsafe { lua_getupvalue(self.state, funcindex, n) };
800        if ptr.is_null() {
801            None
802        } else {
803            let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
804            str::from_utf8(slice).ok()
805        }
806    }
807
808    /// Maps to `lua_setupvalue`.
809    fn set_upvalue(&self, funcindex: Index, n: c_int) -> Option<&str> {
810        let ptr = unsafe { lua_setupvalue(self.state, funcindex, n) };
811        if ptr.is_null() {
812            None
813        } else {
814            let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
815            str::from_utf8(slice).ok()
816        }
817    }
818
819    /// Maps to `lua_upvalueid`.
820    fn upvalue_id(&self, funcindex: Index, n: c_int) -> *mut c_void {
821        unsafe { lua_upvalueid(self.state, funcindex, n) }
822    }
823
824    /// Maps to `lua_upvaluejoin`.
825    fn upvalue_join(&self, fidx1: Index, n1: c_int, fidx2: Index, n2: c_int) {
826        unsafe { lua_upvaluejoin(self.state, fidx1, n1, fidx2, n2) }
827    }
828
829    #[cfg(feature = "std")]
830    /// Maps to `lua_sethook`.
831    fn set_hook(&self, func: Option<lua_Hook>, mask: HookMask, count: c_int) {
832        unsafe { lua_sethook(self.state, func, mask.bits(), count) }
833    }
834
835    /// Maps to `lua_gethook`.
836    fn get_hook(&self) -> Option<lua_Hook> {
837        unsafe { lua_gethook(self.state) }
838    }
839
840    #[cfg(feature = "std")]
841    /// Maps to `lua_gethookmask`.
842    fn get_hook_mask(&self) -> HookMask {
843        let result = unsafe { lua_gethookmask(self.state) };
844        HookMask::from_bits_truncate(result)
845    }
846
847    /// Maps to `lua_gethookcount`.
848    fn get_hook_count(&self) -> c_int {
849        unsafe { lua_gethookcount(self.state) }
850    }
851
852    /// Maps to `luaL_getmetafield`.
853    #[inline(always)]
854    fn get_metafield(&self, obj: Index, e: &CStr) -> bool {
855        let result = unsafe { luaL_getmetafield(self.state, obj, e.as_ptr()) };
856        result != 0
857    }
858
859    /// Maps to `luaL_callmeta`.
860    #[inline(always)]
861    fn call_meta(&self, obj: Index, e: &CStr) -> bool {
862        let result = unsafe { luaL_callmeta(self.state, obj, e.as_ptr()) };
863        result != 0
864    }
865
866    /// [-0, +0, -]
867    #[inline(always)]
868    fn to_string(&self, index: Index) -> *const c_char {
869        unsafe { lua_tolstring(self.state, index, ptr::null_mut()) }
870    }
871
872    /// [-0, +0, -]
873    #[inline(always)]
874    fn tolstring(&self, index: Index, size: &mut usize) -> *const c_char {
875        unsafe { lua_tolstring(self.state, index, size as *mut usize) }
876    }
877
878    /// [-0, +0, -]
879    #[inline(always)]
880    fn to_cfunction(&self, index: Index) -> lua_CFunction {
881        unsafe { lua_tocfunction(self.state, index) }
882    }
883
884    /// Maps to `luaL_tolstring`.
885    /// [-0, +1, -]
886    #[inline(always)]
887    fn cast_string(&self, index: Index) -> Option<&[u8]> {
888        let mut len = 0;
889        let ptr = unsafe { luaL_tolstring(self.state, index, &mut len) };
890        if ptr.is_null() {
891            None
892        } else {
893            Some(unsafe { slice::from_raw_parts(ptr as *const u8, len as usize) })
894        }
895    }
896
897    #[inline(always)]
898    fn to_str<'a>(&'a self, index: Index) -> Option<&'a str> {
899        self.to_bytes(index).and_then(|r| str::from_utf8(r).ok())
900    }
901
902    #[inline(always)]
903    fn to_string_lossy<'a>(&'a self, index: Index) -> Option<Cow<'a, str>> {
904        self.to_bytes(index).map(|r| String::from_utf8_lossy(r))
905    }
906
907    /// Maps to `lua_tolstring`, but allows arbitrary bytes.
908    /// This function returns a reference to the string at the given index,
909    /// on which `to_owned` may be called.
910    fn to_bytes(&self, index: Index) -> Option<&[u8]> {
911        let mut len = 0;
912        let ptr = unsafe { lua_tolstring(self.state, index, &mut len) };
913        if ptr.is_null() {
914            None
915        } else {
916            Some(unsafe { slice::from_raw_parts(ptr as *const u8, len as usize) })
917        }
918    }
919
920    /// Maps to `luaL_argerror`.
921    fn arg_error(&self, arg: Index, extramsg: &CStr) -> ! {
922        unsafe { luaL_argerror(self.state, arg, extramsg.as_ptr()) };
923        unreachable!()
924    }
925
926    /// Maps to `luaL_checknumber`.
927    #[inline(always)]
928    fn check_number(&self, arg: Index) -> lua_Number {
929        unsafe { luaL_checknumber(self.state, arg) }
930    }
931
932    /// Maps to `luaL_optnumber`.
933    #[inline(always)]
934    fn opt_number(&self, arg: Index, def: lua_Number) -> lua_Number {
935        unsafe { luaL_optnumber(self.state, arg, def) }
936    }
937
938    /// Maps to `luaL_checkinteger`.
939    #[inline(always)]
940    fn check_integer(&self, arg: Index) -> lua_Integer {
941        unsafe { luaL_checkinteger(self.state, arg) }
942    }
943
944    /// Maps to `luaL_optinteger`.
945    #[inline(always)]
946    fn opt_integer(&self, arg: Index, def: lua_Integer) -> lua_Integer {
947        unsafe { luaL_optinteger(self.state, arg, def) }
948    }
949
950    /// Maps to `luaL_checkstack`.
951    fn check_stack_msg(&self, sz: c_int, msg: &str) {
952        let c_str = CString::new(msg).unwrap();
953        unsafe { luaL_checkstack(self.state, sz, c_str.as_ptr()) }
954    }
955
956    /// Maps to `luaL_checktype`.
957    #[inline(always)]
958    fn check_type(&self, arg: Index, t: Type) {
959        unsafe { luaL_checktype(self.state, arg, t as c_int) }
960    }
961
962    /// Maps to `luaL_checkany`.
963    #[inline(always)]
964    fn check_any(&self, arg: Index) {
965        unsafe { luaL_checkany(self.state, arg) }
966    }
967
968    /// Maps to `luaL_newmetatable`.
969    #[inline(always)]
970    fn new_metatable(&self, tname: &CStr) -> bool {
971        unsafe { luaL_newmetatable(self.state, tname.as_ptr()) != 0 }
972    }
973
974    /// Maps to `luaL_setmetatable`.
975    #[inline(always)]
976    fn set_metatable_from_registry(&self, tname: &CStr) {
977        unsafe { luaL_setmetatable(self.state, tname.as_ptr()) }
978    }
979
980    /// Maps to `luaL_testudata`.
981    #[inline(always)]
982    fn test_userdata(&self, arg: Index, tname: &CStr) -> *mut c_void {
983        unsafe { luaL_testudata(self.state, arg, tname.as_ptr()) }
984    }
985
986    /// Convenience function that calls `test_userdata` and performs a cast.
987    //#[unstable(reason="this is an experimental function")]
988    #[inline(always)]
989    unsafe fn test_userdata_typed<'a, T>(
990        &'a mut self,
991        arg: Index,
992        tname: &CStr,
993    ) -> Option<&'a mut T> {
994        mem::transmute(self.test_userdata(arg, tname))
995    }
996
997    /// Maps to `luaL_checkudata`.
998    #[inline(always)]
999    fn checkudata<'a, T>(&'a self, arg: Index, tname: &CStr) -> &'a mut T {
1000        unsafe { mem::transmute(luaL_checkudata(self.state, arg, tname.as_ptr())) }
1001    }
1002
1003    /// Maps to `luaL_where`. `where` is a reserved keyword.
1004    #[inline(always)]
1005    fn location(&self, lvl: c_int) {
1006        unsafe { luaL_where(self.state, lvl) }
1007    }
1008
1009    // omitted: luaL_error
1010
1011    /// Maps to `luaL_checkoption`.
1012    fn check_option(&self, arg: Index, def: Option<&str>, lst: &[&str]) -> usize {
1013        let mut vec: Vec<*const c_char> = Vec::with_capacity(lst.len() + 1);
1014        let cstrs: Vec<CString> = lst.iter().map(|ent| CString::new(*ent).unwrap()).collect();
1015        for ent in cstrs.iter() {
1016            vec.push(ent.as_ptr());
1017        }
1018        vec.push(ptr::null());
1019        let result = match def {
1020            Some(def) => unsafe {
1021                let c_str = CString::new(def).unwrap();
1022                luaL_checkoption(self.state, arg, c_str.as_ptr(), vec.as_ptr())
1023            },
1024            None => unsafe { luaL_checkoption(self.state, arg, ptr::null(), vec.as_ptr()) },
1025        };
1026        result as usize
1027    }
1028
1029    /// luaL_ref [-1, +0, m]
1030    #[inline(always)]
1031    fn reference(&self, t: Index) -> Reference {
1032        let result = unsafe { luaL_ref(self.state, t) };
1033        Reference(result)
1034    }
1035
1036    /// Maps to `luaL_unref`.
1037    #[inline(always)]
1038    fn unreference(&self, t: Index, reference: Reference) {
1039        unsafe { luaL_unref(self.state, t, reference.value()) }
1040    }
1041
1042    /// Maps to `luaL_loadfilex`.
1043    fn load_filex(&self, filename: &str, mode: &str) -> i32 {
1044        unsafe {
1045            let filename_c_str = CString::new(filename).unwrap();
1046            let mode_c_str = CString::new(mode).unwrap();
1047            luaL_loadfilex(self.state, filename_c_str.as_ptr(), mode_c_str.as_ptr())
1048        }
1049    }
1050
1051    /// Maps to `luaL_loadfile`.
1052    fn load_file(&self, filename: &str) -> i32 {
1053        let c_str = CString::new(filename).unwrap();
1054        unsafe { luaL_loadfile(self.state, c_str.as_ptr()) }
1055    }
1056
1057    /// [-0, +1, -]
1058    fn load_buffer<F: AsRef<[u8]>>(&self, source: F, chunk_name: Option<&str>) -> i32 {
1059        let buffer = source.as_ref();
1060        let chunk = chunk_name.and_then(|name| CString::new(name).ok());
1061        unsafe {
1062            luaL_loadbuffer(
1063                self.state,
1064                buffer.as_ptr() as *const c_char,
1065                buffer.len(),
1066                chunk.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null()),
1067            )
1068        }
1069    }
1070
1071    /// Maps to `luaL_loadbufferx`.
1072    fn load_bufferx(&self, buff: &[u8], name: &str, mode: &str) -> i32 {
1073        let name_c_str = CString::new(name).unwrap();
1074        let mode_c_str = CString::new(mode).unwrap();
1075        unsafe {
1076            luaL_loadbufferx(
1077                self.state,
1078                buff.as_ptr() as *const _,
1079                buff.len() as size_t,
1080                name_c_str.as_ptr(),
1081                mode_c_str.as_ptr(),
1082            )
1083        }
1084    }
1085
1086    /// Maps to `luaL_loadstring`.
1087    fn load_string(&self, source: &str) -> i32 {
1088        let c_str = CString::new(source).unwrap();
1089        unsafe { luaL_loadstring(self.state, c_str.as_ptr()) }
1090    }
1091
1092    /// Maps to `lua_dump`.
1093    #[inline]
1094    fn dump(&self, mut writer: impl FnMut(&[u8]), strip: bool) -> c_int {
1095        use core::mem::transmute;
1096        unsafe extern "C-unwind" fn dump_wrapper(
1097            l: *mut lua_State,
1098            p: *const c_void,
1099            sz: usize,
1100            ud: *mut c_void,
1101        ) -> c_int {
1102            let callback = transmute::<_, &mut &mut dyn FnMut(&[u8])>(ud);
1103            callback(core::slice::from_raw_parts(p as *const u8, sz));
1104            0
1105        }
1106        let writer: &mut dyn FnMut(&[u8]) = &mut writer;
1107        unsafe { lua_dump(self.state, dump_wrapper, transmute(&writer), strip as c_int) }
1108    }
1109
1110    /// Maps to `luaL_len`.
1111    fn len_direct(&self, index: Index) -> lua_Integer {
1112        unsafe { luaL_len(self.state, index) }
1113    }
1114
1115    /// Maps to `luaL_gsub`.
1116    fn gsub(&self, s: &str, p: &str, r: &str) -> &str {
1117        let s_c_str = CString::new(s).unwrap();
1118        let p_c_str = CString::new(p).unwrap();
1119        let r_c_str = CString::new(r).unwrap();
1120        let ptr = unsafe {
1121            luaL_gsub(
1122                self.state,
1123                s_c_str.as_ptr(),
1124                p_c_str.as_ptr(),
1125                r_c_str.as_ptr(),
1126            )
1127        };
1128        let slice = unsafe { CStr::from_ptr(ptr).to_bytes() };
1129        str::from_utf8(slice).unwrap()
1130    }
1131
1132    /// Maps to `luaL_setfuncs`.
1133    fn set_fns(&self, l: &[(&str, lua_CFunction)], nup: c_int) {
1134        let mut reg: Vec<luaL_Reg> = Vec::with_capacity(l.len() + 1);
1135        let ents: Vec<(CString, lua_CFunction)> = l
1136            .iter()
1137            .map(|&(s, f)| (CString::new(s).unwrap(), f))
1138            .collect();
1139        for &(ref s, f) in ents.iter() {
1140            reg.push(luaL_Reg {
1141                name: s.as_ptr(),
1142                func: f,
1143            });
1144        }
1145        reg.push(luaL_Reg {
1146            name: ptr::null(),
1147            func: None,
1148        });
1149        unsafe { luaL_setfuncs(self.state, reg.as_ptr(), nup) }
1150    }
1151
1152    /// Maps to `luaL_getsubtable`.
1153    #[inline(always)]
1154    fn get_subtable(&self, idx: Index, fname: &CStr) -> bool {
1155        unsafe { luaL_getsubtable(self.state, idx, fname.as_ptr()) != 0 }
1156    }
1157
1158    /// Maps to `luaL_traceback`.
1159    #[inline(always)]
1160    fn traceback(&self, state: *mut lua_State, msg: &CStr, level: c_int) {
1161        unsafe { luaL_traceback(self.state, state, msg.as_ptr(), level) }
1162    }
1163
1164    /// Maps to `luaL_requiref`.
1165    #[inline(always)]
1166    fn requiref(&self, modname: &CStr, openf: CFunction, glb: bool) {
1167        unsafe { luaL_requiref(self.state, modname.as_ptr(), Some(openf), glb as c_int) }
1168    }
1169
1170    /// Maps to `luaL_argcheck`.
1171    #[inline(always)]
1172    fn arg_check(&self, cond: bool, arg: Index, extramsg: &str) {
1173        let c_str = CString::new(extramsg).unwrap();
1174        unsafe { luaL_argcheck(self.state, cond as c_int, arg, c_str.as_ptr()) }
1175    }
1176
1177    /// Maps to `luaL_checklstring`.
1178    fn check_string(&self, n: Index) -> &str {
1179        let mut size = 0;
1180        let ptr = unsafe { luaL_checklstring(self.state, n, &mut size) };
1181        let slice = unsafe { slice::from_raw_parts(ptr as *const u8, size as usize) };
1182        str::from_utf8(slice).unwrap()
1183    }
1184
1185    /// Maps to `luaL_optlstring`.
1186    fn opt_string<'a>(&'a mut self, n: Index, default: &'a str) -> &'a str {
1187        let mut size = 0;
1188        let c_str = CString::new(default).unwrap();
1189        let ptr = unsafe { luaL_optlstring(self.state, n, c_str.as_ptr(), &mut size) };
1190        if ptr == c_str.as_ptr() {
1191            default
1192        } else {
1193            let slice = unsafe { slice::from_raw_parts(ptr as *const u8, size as usize) };
1194            str::from_utf8(slice).unwrap()
1195        }
1196    }
1197
1198    /// Maps to `luaL_getmetatable`.
1199    #[inline(always)]
1200    fn get_metatable_from_registry(&self, tname: &str) {
1201        let c_str = CString::new(tname).unwrap();
1202        unsafe { luaL_getmetatable(self.state, c_str.as_ptr()) }
1203    }
1204
1205    /// Before call push, stack should be checked by .check_stack()
1206    #[inline(always)]
1207    fn push<T: ToLua>(&self, value: T) -> Result<(), Error> {
1208        match T::__PUSH {
1209            Some(push) => {
1210                #[cfg(debug_assertions)]
1211                let top = self.get_top();
1212                push(value, self)?;
1213                #[cfg(debug_assertions)]
1214                assert_eq!(top + 1, self.get_top(), "{}", core::any::type_name::<T>());
1215            }
1216            None => {
1217                let top = self.get_top();
1218                self.push_value(value.to_lua(self)?.index);
1219                if !self.clear_with_keep_top_one(top) {
1220                    panic!(
1221                        "stack should be increased, top: {top} after: {}",
1222                        self.get_top()
1223                    );
1224                }
1225            }
1226        }
1227        Ok(())
1228    }
1229}
1230
1231/// Arithmetic operations for `lua_arith`.
1232#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1233pub enum Arithmetic {
1234    Add = LUA_OPADD as isize,
1235    Sub = LUA_OPSUB as isize,
1236    Mul = LUA_OPMUL as isize,
1237    Mod = LUA_OPMOD as isize,
1238    Pow = LUA_OPPOW as isize,
1239    Div = LUA_OPDIV as isize,
1240    IDiv = LUA_OPIDIV as isize,
1241    BAnd = LUA_OPBAND as isize,
1242    BOr = LUA_OPBOR as isize,
1243    BXor = LUA_OPBXOR as isize,
1244    Shl = LUA_OPSHL as isize,
1245    Shr = LUA_OPSHR as isize,
1246    Unm = LUA_OPUNM as isize,
1247    BNot = LUA_OPBNOT as isize,
1248}
1249
1250/// Comparison operations for `lua_compare`.
1251#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1252pub enum Comparison {
1253    Eq = LUA_OPEQ as isize,
1254    Lt = LUA_OPLT as isize,
1255    Le = LUA_OPLE as isize,
1256}
1257
1258/// Represents all possible Lua data types.
1259#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1260pub enum Type {
1261    None = LUA_TNONE as isize,
1262    Nil = LUA_TNIL as isize,
1263    Boolean = LUA_TBOOLEAN as isize,
1264    LightUserdata = LUA_TLIGHTUSERDATA as isize,
1265    Number = LUA_TNUMBER as isize,
1266    String = LUA_TSTRING as isize,
1267    Table = LUA_TTABLE as isize,
1268    Function = LUA_TFUNCTION as isize,
1269    Userdata = LUA_TUSERDATA as isize,
1270    Thread = LUA_TTHREAD as isize,
1271    Invalid,
1272}
1273
1274impl core::fmt::Display for Type {
1275    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1276        match self {
1277            Type::None => write!(f, "none"),
1278            Type::Nil => write!(f, "nil"),
1279            Type::Boolean => write!(f, "boolean"),
1280            Type::LightUserdata => write!(f, "lightuserdata"),
1281            Type::Number => write!(f, "number"),
1282            Type::String => write!(f, "string"),
1283            Type::Table => write!(f, "table"),
1284            Type::Function => write!(f, "function"),
1285            Type::Userdata => write!(f, "userdata"),
1286            Type::Thread => write!(f, "thread"),
1287            Type::Invalid => write!(f, "invalid"),
1288        }
1289    }
1290}
1291
1292impl Type {
1293    fn from_c_int(i: c_int) -> Type {
1294        match i {
1295            LUA_TNIL => Type::Nil,
1296            LUA_TBOOLEAN => Type::Boolean,
1297            LUA_TLIGHTUSERDATA => Type::LightUserdata,
1298            LUA_TNUMBER => Type::Number,
1299            LUA_TSTRING => Type::String,
1300            LUA_TTABLE => Type::Table,
1301            LUA_TFUNCTION => Type::Function,
1302            LUA_TUSERDATA => Type::Userdata,
1303            LUA_TTHREAD => Type::Thread,
1304            _ => Type::Invalid,
1305        }
1306    }
1307
1308    pub fn is_none_or_nil(&self) -> bool {
1309        matches!(*self, Type::None | Type::Nil)
1310    }
1311}
1312
1313/// Options for the Lua garbage collector.
1314#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1315pub enum GcOption {
1316    Stop = LUA_GCSTOP as isize,
1317    Restart = LUA_GCRESTART as isize,
1318    Collect = LUA_GCCOLLECT as isize,
1319    Count = LUA_GCCOUNT as isize,
1320    CountBytes = LUA_GCCOUNTB as isize,
1321    Step = LUA_GCSTEP as isize,
1322    SetPause = LUA_GCSETPAUSE as isize,
1323    SetStepMul = LUA_GCSETSTEPMUL as isize,
1324    IsRunning = LUA_GCISRUNNING as isize,
1325}
1326
1327/// Mode of the Lua garbage collector (GC)
1328#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1329pub enum GCMode {
1330    Incremental,
1331    Generational,
1332}
1333
1334/// Status of a Lua state.
1335#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1336pub enum ThreadStatus {
1337    Ok = LUA_OK as isize,
1338    Yield = LUA_YIELD as isize,
1339    RuntimeError = LUA_ERRRUN as isize,
1340    SyntaxError = LUA_ERRSYNTAX as isize,
1341    MemoryError = LUA_ERRMEM as isize,
1342    // GcError = LUA_ERRGCMM as isize,
1343    MessageHandlerError = LUA_ERRERR as isize,
1344    FileError = LUA_ERRFILE as isize,
1345}
1346
1347impl ThreadStatus {
1348    pub(crate) fn from_c_int(i: c_int) -> ThreadStatus {
1349        match i {
1350            LUA_OK => ThreadStatus::Ok,
1351            LUA_YIELD => ThreadStatus::Yield,
1352            LUA_ERRRUN => ThreadStatus::RuntimeError,
1353            LUA_ERRSYNTAX => ThreadStatus::SyntaxError,
1354            LUA_ERRMEM => ThreadStatus::MemoryError,
1355            // LUA_ERRGCMM => ThreadStatus::GcError,
1356            LUA_ERRERR => ThreadStatus::MessageHandlerError,
1357            LUA_ERRFILE => ThreadStatus::FileError,
1358            _ => panic!("Unknown Lua error code: {}", i),
1359        }
1360    }
1361
1362    pub fn is_ok(self) -> bool {
1363        matches!(self, Self::Ok)
1364    }
1365
1366    /// Returns `true` for error statuses and `false` for `Ok` and `Yield`.
1367    pub fn is_err(self) -> bool {
1368        match self {
1369            ThreadStatus::RuntimeError
1370            | ThreadStatus::SyntaxError
1371            | ThreadStatus::MemoryError
1372            // | ThreadStatus::GcError
1373            | ThreadStatus::MessageHandlerError
1374            | ThreadStatus::FileError => true,
1375            ThreadStatus::Ok | ThreadStatus::Yield => false,
1376        }
1377    }
1378}
1379
1380/// Type of Lua references generated through `reference` and `unreference`.
1381#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1382pub struct Reference(pub c_int);
1383
1384impl Default for Reference {
1385    fn default() -> Self {
1386        NOREF
1387    }
1388}
1389
1390/// The result of `reference` for `nil` values.
1391pub const REFNIL: Reference = Reference(LUA_REFNIL);
1392
1393/// A value that will never be returned by `reference`.
1394pub const NOREF: Reference = Reference(LUA_REFNIL);
1395
1396impl Reference {
1397    /// Returns `true` if this reference is equal to `REFNIL`.
1398    pub fn is_nil_ref(self) -> bool {
1399        self == REFNIL
1400    }
1401
1402    /// Returns `true` if this reference is equal to `NOREF`.
1403    pub fn is_no_ref(self) -> bool {
1404        self == NOREF
1405    }
1406
1407    /// Convenience function that returns the value of this reference.
1408    pub fn value(self) -> c_int {
1409        let Reference(value) = self;
1410        value
1411    }
1412}
1413
1414impl From<c_int> for Reference {
1415    fn from(i: c_int) -> Self {
1416        Self(i)
1417    }
1418}
1419
1420#[cfg(feature = "std")]
1421bitflags::bitflags! {
1422    /// Hook point masks for `lua_sethook`.
1423    pub struct HookMask: c_int {
1424        /// Called when the interpreter calls a function.
1425        const MASKCALL  = LUA_MASKCALL;
1426        /// Called when the interpreter returns from a function.
1427        const MASKRET   = LUA_MASKRET;
1428        /// Called when the interpreter is about to start the execution of a new line of code.
1429        const MASKLINE  = LUA_MASKLINE;
1430        /// Called after the interpreter executes every `count` instructions.
1431        const MASKCOUNT = LUA_MASKCOUNT;
1432    }
1433}
1434
1435impl lua_Debug {
1436    pub fn source(&self) -> Option<Cow<str>> {
1437        if self.source.is_null() {
1438            None
1439        } else {
1440            Some(unsafe { CStr::from_ptr(self.source).to_string_lossy() })
1441        }
1442    }
1443
1444    pub fn short_src(&self) -> Cow<str> {
1445        unsafe { CStr::from_ptr(self.short_src.as_ptr()).to_string_lossy() }
1446    }
1447
1448    pub fn name(&self) -> Option<Cow<str>> {
1449        if self.name.is_null() {
1450            None
1451        } else {
1452            Some(unsafe { CStr::from_ptr(self.name).to_string_lossy() })
1453        }
1454    }
1455
1456    pub fn what(&self) -> Option<Cow<str>> {
1457        if self.what.is_null() {
1458            None
1459        } else {
1460            Some(unsafe { CStr::from_ptr(self.what).to_string_lossy() })
1461        }
1462    }
1463
1464    pub fn namewhat(&self) -> Option<Cow<str>> {
1465        if self.namewhat.is_null() {
1466            None
1467        } else {
1468            Some(unsafe { CStr::from_ptr(self.namewhat).to_string_lossy() })
1469        }
1470    }
1471}