ezlua/
value.rs

1//! Implementation to lua value
2
3use alloc::{borrow::Cow, vec::Vec};
4use core::ffi::{c_char, c_void};
5use core::ops;
6
7use crate::{
8    convert::*,
9    error::*,
10    ffi::{self, lua_Integer, lua_Number, lua_tostring},
11    luaapi::{Reference, Type, UnsafeLuaApi},
12    marker::RegVal,
13    prelude::ArgRef,
14    state::*,
15    str::CStr,
16    userdata::UserData,
17};
18
19/// Value reference on the lua stack
20pub struct ValRef<'a> {
21    pub(crate) state: &'a State,
22    pub(crate) index: Index,
23}
24
25impl Clone for ValRef<'_> {
26    #[inline(always)]
27    fn clone(&self) -> Self {
28        self.state.val(self.index)
29    }
30}
31
32impl<'a> core::fmt::Debug for ValRef<'a> {
33    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
34        let mut ds = f.debug_struct("ValRef");
35        ds.field("index", &self.index)
36            .field("type", &self.type_of());
37        match self.type_of() {
38            Type::Boolean => ds.field("value", &self.to_bool()),
39            Type::Userdata | Type::LightUserdata => {
40                ds.field("value", &self.state.to_userdata(self.index))
41            }
42            Type::Number => ds.field("value", &self.to_number()),
43            Type::String => ds.field("value", &self.to_string_lossy().unwrap_or_default()),
44            Type::Table | Type::Thread | Type::Function => {
45                ds.field("value", &self.state.to_pointer(self.index))
46            }
47            _ => ds.field("value", &()),
48        }
49        .finish()
50    }
51}
52
53impl Drop for ValRef<'_> {
54    #[track_caller]
55    #[inline(always)]
56    fn drop(&mut self) {
57        self.state.drop_valref(self);
58    }
59}
60
61impl<'a> ValRef<'a> {
62    #[inline]
63    pub fn state(&self) -> &'a State {
64        self.state
65    }
66
67    /// Type of this value
68    #[inline]
69    pub fn type_of(&self) -> Type {
70        self.state.type_of(self.index)
71    }
72
73    #[inline]
74    pub fn is_nil(&self) -> bool {
75        self.state.is_nil(self.index)
76    }
77
78    #[inline]
79    pub fn is_integer(&self) -> bool {
80        self.state.is_integer(self.index)
81    }
82
83    #[inline]
84    pub fn is_table(&self) -> bool {
85        self.state.is_table(self.index)
86    }
87
88    #[inline]
89    pub fn is_function(&self) -> bool {
90        self.state.is_function(self.index)
91    }
92
93    pub fn check_safe_index(&self) -> Result<()> {
94        if self.state.safe_index(self.index) {
95            Ok(())
96        } else {
97            Err("ref is not safe").lua_result()
98        }
99    }
100
101    pub fn to_safe_bytes(&self) -> Result<&'a [u8]> {
102        self.check_type(Type::String)?;
103        self.state
104            .to_safe_bytes(self.index)
105            .ok_or_else(|| Error::Convert("safe bytes".into()))
106    }
107
108    #[inline]
109    pub fn to_safe_str(&self) -> Result<&'a str> {
110        core::str::from_utf8(self.to_safe_bytes()?).lua_result()
111    }
112
113    #[inline]
114    pub fn to_bytes(&self) -> Option<&[u8]> {
115        self.check_type(Type::String).ok()?;
116        self.state.to_bytes(self.index)
117    }
118
119    #[inline]
120    pub fn to_str(&self) -> Option<&str> {
121        self.check_type(Type::String).ok()?;
122        self.state.to_str(self.index)
123    }
124
125    #[inline]
126    pub fn to_string_lossy(&self) -> Option<Cow<str>> {
127        self.state.to_string_lossy(self.index)
128    }
129
130    #[inline]
131    pub fn to_bool(&self) -> bool {
132        self.state.to_bool(self.index)
133    }
134
135    #[inline]
136    pub fn to_integer(&self) -> lua_Integer {
137        self.state.to_integer(self.index)
138    }
139
140    #[inline]
141    pub fn to_number(&self) -> lua_Number {
142        self.state.to_number(self.index)
143    }
144
145    #[inline]
146    pub fn to_pointer(&self) -> *const c_void {
147        self.state.to_pointer(self.index)
148    }
149
150    #[inline]
151    pub fn to_cstr_ptr(&self) -> *const c_char {
152        unsafe { lua_tostring(self.state.state, self.index) }
153    }
154
155    /// Call `tostring` if this value is not a string
156    pub fn tostring(&self) -> Cow<str> {
157        self.to_string_lossy().unwrap_or_else(|| {
158            self.state
159                .global()
160                .get("tostring")
161                .and_then(|tostring| tostring.pcall(self))
162                .unwrap_or_default()
163        })
164    }
165
166    /// Index number of this value on the lua stack
167    #[inline]
168    pub fn index(&self) -> Index {
169        self.index
170    }
171
172    #[inline(always)]
173    pub fn check_type(&self, ty: Type) -> Result<()> {
174        self.state.check_type(self.index, ty)
175    }
176
177    pub fn check_type2(&self, ty1: Type, ty2: Type) -> Result<()> {
178        let ty = self.type_of();
179        if ty == ty1 || ty == ty2 {
180            Ok(())
181        } else {
182            Err(Error::TypeNotMatch(ty))
183        }
184    }
185
186    /// Cast a lua value to its rust type, wrapper of [`FromLua::from_lua`]
187    ///
188    /// See [`FromLua`]
189    #[inline(always)]
190    pub fn cast_into<T: FromLua<'a> + 'a>(self) -> Result<T> {
191        FromLua::from_lua(self.state, self)
192    }
193
194    /// Alias to `cast_into()`, not take the ownship, but only convert to static-lifetime types
195    #[inline]
196    pub fn cast<T: FromLua<'a> + 'static>(&self) -> Result<T> {
197        self.clone().cast_into()
198    }
199
200    pub(crate) fn getf(&self, k: &CStr) -> ValRef {
201        self.state.check_stack(1).expect("stack");
202        self.state.get_field(self.index, k);
203        self.state.top_val()
204    }
205
206    #[inline]
207    pub(crate) fn setf<V: ToLua>(&self, k: &CStr, v: V) -> Result<()> {
208        self.state.check_stack(1)?;
209        self.state.push(v)?;
210        self.state.set_field(self.index, k);
211        Ok(())
212    }
213
214    /// Get value associated to integer key, equivalent to `return self[i]` in lua
215    pub fn geti(&self, i: impl Into<lua_Integer>) -> Result<ValRef<'a>> {
216        if self.has_metatable() {
217            unsafe extern "C-unwind" fn protect_get(l: *mut ffi::lua_State) -> i32 {
218                ffi::lua_geti(l, 1, ffi::lua_tointeger(l, 2));
219                1
220            }
221            self.state
222                .protect_call((ArgRef(self.index), i.into()), protect_get)
223        } else {
224            self.check_type2(Type::Table, Type::Userdata)?;
225            self.state.check_stack(1)?;
226            self.state.geti(self.index, i.into());
227            Ok(self.state.top_val())
228        }
229    }
230
231    /// Set value with integer key, equivalent to `self[i] = v` in lua
232    pub fn seti<V: ToLua>(&self, i: impl Into<lua_Integer>, v: V) -> Result<()> {
233        if self.has_metatable() {
234            unsafe extern "C-unwind" fn protect_set(l: *mut ffi::lua_State) -> i32 {
235                ffi::lua_seti(l, 1, ffi::lua_tointeger(l, 2));
236                0
237            }
238            self.state
239                .protect_call((ArgRef(self.index), i.into(), v), protect_set)
240        } else {
241            self.check_type2(Type::Table, Type::Userdata)?;
242            self.state.check_stack(1)?;
243            self.state.push(v)?;
244            self.state.seti(self.index, i.into());
245            Ok(())
246        }
247    }
248
249    /// Get length of the value, equivalent to `return #self` in lua
250    #[inline]
251    pub fn len(&self) -> Result<ValRef<'a>> {
252        if self.has_metatable() {
253            unsafe extern "C-unwind" fn protect(l: *mut ffi::lua_State) -> i32 {
254                ffi::lua_len(l, 1);
255                0
256            }
257            self.state.protect_call(ArgRef(self.index), protect)
258        } else {
259            self.state.len(self.index);
260            Ok(self.state.top_val())
261        }
262    }
263
264    /// Set value with any key, equivalent to `self[k] = v` in lua
265    pub fn set<K: ToLua, V: ToLua>(&self, k: K, v: V) -> Result<()> {
266        if self.has_metatable() {
267            unsafe extern "C-unwind" fn protect_set(l: *mut ffi::lua_State) -> i32 {
268                ffi::lua_settable(l, 1);
269                0
270            }
271            self.state
272                .protect_call((ArgRef(self.index), k, v), protect_set)
273        } else {
274            self.as_table()
275                .ok_or_else(|| Error::TypeNotMatch(self.type_of()))?
276                .raw_set(k, v)
277        }
278    }
279
280    /// Get value associated to key, equivalent to `return self[k]` in lua
281    pub fn get<K: ToLua>(&self, key: K) -> Result<ValRef<'a>> {
282        if self.has_metatable() {
283            unsafe extern "C-unwind" fn protect_get(l: *mut ffi::lua_State) -> i32 {
284                ffi::lua_gettable(l, 1);
285                1
286            }
287            self.state
288                .protect_call((ArgRef(self.index), key), protect_get)
289        } else {
290            self.as_table()
291                .ok_or_else(|| Error::TypeNotMatch(self.type_of()))?
292                .raw_get(key)
293        }
294    }
295
296    #[inline]
297    pub fn getopt<K: ToLua, V: FromLua<'a> + 'a>(&self, k: K) -> Result<Option<V>> {
298        Ok(self.get(k)?.cast_into().ok())
299    }
300
301    /// Call this value as a function
302    #[inline(always)]
303    pub fn pcall<T: ToLuaMulti, R: FromLuaMulti<'a>>(&self, args: T) -> Result<R> {
304        self.state.pcall_trace(ArgRef(self.index), args)
305    }
306
307    /// Invoke `pcall()` without return value
308    #[inline(always)]
309    pub fn pcall_void<T: ToLuaMulti>(&self, args: T) -> Result<()> {
310        self.pcall(args)
311    }
312
313    pub fn has_metatable(&self) -> bool {
314        let result = self.state.check_stack(1).is_ok() && self.state.get_metatable(self.index);
315        if result {
316            self.state.pop(1);
317        }
318        result
319    }
320
321    /// Get metatable of lua table or userdata
322    pub fn metatable(&self) -> Result<Option<Table<'a>>> {
323        self.state.check_stack(1)?;
324        Ok(if self.state.get_metatable(self.index) {
325            Some(self.state.top_val().try_into()?)
326        } else {
327            None
328        })
329    }
330
331    /// Set metatable for lua table or userdata
332    pub fn set_metatable(&self, t: Table) -> Result<()> {
333        self.state.check_stack(1)?;
334        self.state.pushval(t.0);
335        self.state.set_metatable(self.index);
336        Ok(())
337    }
338
339    /// Remove metatable for lua table or userdata
340    pub fn remove_metatable(&self) {
341        self.state.check_stack(1).expect("check");
342        // TODO: thread lock
343        self.state.push_nil();
344        self.state.set_metatable(self.index);
345    }
346
347    /// Call a metamethod
348    #[inline(always)]
349    pub fn call_metamethod<T: ToLuaMulti, R: FromLuaMulti<'a>>(
350        &self,
351        m: &str,
352        args: T,
353    ) -> Result<R> {
354        self.metatable()?
355            .ok_or_else(|| Error::runtime("no metatable"))?
356            .raw_get(m)?
357            .pcall(args)
358    }
359
360    /// Close this value, if userdata, the subsequent access to it in lua is invalid
361    #[inline(always)]
362    pub fn close_and_remove_metatable(self) -> Result<()> {
363        self.call_close_and_remove_metatable()
364    }
365
366    pub fn call_close_and_remove_metatable(&self) -> Result<()> {
367        self.call_metamethod("__close", ArgRef(self.index))
368            .map(|()| self.remove_metatable())
369    }
370
371    /// Tests whether two lua values are equal without metamethod triggers
372    pub fn raw_equal(&self, other: &Self) -> bool {
373        self.state.raw_equal(self.index, other.index)
374    }
375
376    /// Get length of the string/userdata/table without metamethod triggers
377    #[inline]
378    pub fn raw_len(&self) -> usize {
379        self.state.raw_len(self.index)
380    }
381
382    pub fn checked_into_value(self) -> Option<Value<'a>> {
383        Some(match self.type_of() {
384            Type::None | Type::Invalid => return None,
385            Type::Nil => Value::Nil,
386            Type::Number => {
387                if self.is_integer() {
388                    Value::Integer(self.to_integer())
389                } else {
390                    Value::Number(self.to_number())
391                }
392            }
393            Type::Boolean => Value::Bool(self.to_bool()),
394            Type::LightUserdata => Value::LightUserdata(self.state.to_userdata(self.index)),
395            Type::String => Value::String(LuaString(self)),
396            Type::Table => Value::Table(Table(self)),
397            Type::Function => Value::Function(Function(self)),
398            Type::Userdata => Value::UserData(LuaUserData(self)),
399            Type::Thread => Value::Thread(LuaThread(self)),
400        })
401    }
402
403    pub fn into_registry_value(self) -> Result<RegVal> {
404        let s = self.state;
405        s.registry_value(self)
406    }
407
408    pub fn into_value(self) -> Value<'a> {
409        match self.type_of() {
410            Type::None | Type::Invalid => Value::None,
411            Type::Nil => Value::Nil,
412            Type::Number => {
413                if self.is_integer() {
414                    Value::Integer(self.to_integer())
415                } else {
416                    Value::Number(self.to_number())
417                }
418            }
419            Type::Boolean => Value::Bool(self.to_bool()),
420            Type::LightUserdata => Value::LightUserdata(self.state.to_userdata(self.index)),
421            Type::String => Value::String(LuaString(self)),
422            Type::Table => Value::Table(Table(self)),
423            Type::Function => Value::Function(Function(self)),
424            Type::Userdata => Value::UserData(LuaUserData(self)),
425            Type::Thread => Value::Thread(LuaThread(self)),
426        }
427    }
428
429    /// Return Some(self) if type is neither Type::Invalid nor Type::None
430    pub fn check_valid(self) -> Option<Self> {
431        match self.type_of() {
432            Type::Invalid | Type::None => None,
433            _ => Some(self),
434        }
435    }
436
437    /// [+(0|1), 0, -]
438    pub(crate) fn ensure_top(self) {
439        if self.index < self.state.get_top() {
440            self.state.push_value(self.index);
441        } else {
442            debug_assert!(self.index == self.state.get_top());
443            core::mem::forget(self);
444        }
445    }
446}
447
448/// Iterator for table traversing, like `pairs` in lua
449pub struct TableIter<'a, V: AsRef<Table<'a>>> {
450    val: V,
451    key: Option<ValRef<'a>>,
452}
453
454impl<'a, V: AsRef<Table<'a>>> Iterator for TableIter<'a, V> {
455    type Item = (ValRef<'a>, ValRef<'a>);
456
457    fn next(&mut self) -> Option<Self::Item> {
458        let t = self.val.as_ref();
459        t.state.check_stack(3).expect("stack");
460        self.key.take().expect("next key must exists").ensure_top();
461        if t.state.next(t.index) {
462            let (k, val) = if let Some(val) = t.state.try_replace_top() {
463                (val.state.top_val(), val)
464            } else {
465                (t.state.val_without_push(-2), t.state.val_without_push(-1))
466            };
467            let key = k.clone();
468            self.key.replace(k);
469            Some((key, val))
470        } else {
471            None
472        }
473    }
474}
475
476/// Typed enumeration for lua value
477#[derive(Debug, Clone, Default)]
478pub enum Value<'a> {
479    None,
480    #[default]
481    Nil,
482    Bool(bool),
483    Integer(lua_Integer),
484    Number(lua_Number),
485    LightUserdata(*mut c_void),
486    String(LuaString<'a>),
487    Table(Table<'a>),
488    Function(Function<'a>),
489    UserData(LuaUserData<'a>),
490    Thread(LuaThread<'a>),
491}
492
493#[cfg(feature = "unsafe_send_sync")]
494unsafe impl Send for Value<'_> {}
495#[cfg(feature = "unsafe_send_sync")]
496unsafe impl Sync for Value<'_> {}
497
498impl<'a> Value<'a> {
499    pub fn light_userdata<T: Sized>(p: *const T) -> Self {
500        Value::LightUserdata(p as usize as _)
501    }
502}
503
504/// Represents a lua table on the stack
505#[derive(Debug, Clone, derive_more::Deref)]
506pub struct Table<'l>(pub(crate) ValRef<'l>);
507
508/// Represents a lua function on the stack
509#[derive(Debug, Clone, derive_more::Deref)]
510pub struct Function<'l>(pub(crate) ValRef<'l>);
511
512/// Represents a lua string on the stack
513#[derive(Debug, Clone, derive_more::Deref)]
514pub struct LuaString<'l>(pub(crate) ValRef<'l>);
515
516/// Represents a lua thread on the stack
517#[derive(Debug, Clone, derive_more::Deref)]
518pub struct LuaThread<'l>(pub(crate) ValRef<'l>);
519
520/// Represents a lua userdata on the stack
521#[derive(Debug, Clone, derive_more::Deref)]
522pub struct LuaUserData<'l>(pub(crate) ValRef<'l>);
523
524macro_rules! impl_wrap {
525    ($t:ty, $lt:expr, $m:ident) => {
526        impl<'a> TryFrom<ValRef<'a>> for $t {
527            type Error = crate::error::Error;
528
529            fn try_from(val: ValRef<'a>) -> Result<Self> {
530                let t = val.type_of();
531                if t == $lt {
532                    Ok(Self(val))
533                } else {
534                    Err(Error::TypeNotMatch(t))
535                }
536            }
537        }
538
539        // impl<'a> From<ValRef<'a>> for $t {
540        //     fn from(val: ValRef<'a>) -> Self {
541        //         assert_eq!(val.type_of(), $lt);
542        //         Self(val)
543        //     }
544        // }
545
546        impl<'a> Into<ValRef<'a>> for $t {
547            fn into(self) -> ValRef<'a> {
548                self.0
549            }
550        }
551
552        impl<'a> ToLua for $t {
553            const __PUSH: Option<fn(Self, &State) -> Result<()>> =
554                Some(|this, s: &State| Ok(s.pushval(this.0)));
555        }
556
557        impl<'a> FromLua<'a> for $t {
558            fn from_lua(_: &'a State, val: ValRef<'a>) -> Result<Self> {
559                val.check_type($lt).map(|_| Self(val))
560            }
561        }
562
563        impl<'a> ValRef<'a> {
564            pub fn $m(&self) -> Option<&$t> {
565                if self.type_of() == $lt {
566                    unsafe { (self as *const _ as *const $t).as_ref() }
567                } else {
568                    None
569                }
570            }
571        }
572    };
573}
574
575impl_wrap!(Table<'a>, Type::Table, as_table);
576impl_wrap!(Function<'a>, Type::Function, as_function);
577impl_wrap!(LuaString<'a>, Type::String, as_string);
578impl_wrap!(LuaThread<'a>, Type::Thread, as_thread);
579impl_wrap!(LuaUserData<'a>, Type::Userdata, as_userdata);
580
581impl<'l> Table<'l> {
582    /// Get value with a lightuserdata key, commonly is a function pointer
583    #[inline]
584    pub fn getp<T>(&self, p: *const T) -> Result<ValRef> {
585        self.state.check_stack(1)?;
586        self.state.raw_getp(self.index, p);
587        Ok(self.state.top_val())
588    }
589
590    /// Set value with a lightuserdata key
591    #[inline]
592    pub fn setp<T, V: ToLua>(&self, k: *const T, v: V) -> Result<()> {
593        self.state.check_stack(1)?;
594        self.state.push(v)?;
595        self.state.raw_setp(self.index, k);
596        Ok(())
597    }
598
599    #[inline]
600    pub fn reference<V: ToLua>(&self, v: V) -> Result<Reference> {
601        self.state.check_stack(1)?;
602        self.state.push(v)?;
603        Ok(self.state.reference(self.index))
604    }
605
606    #[inline]
607    pub fn unreference(&self, r: Reference) {
608        self.state.unreference(self.index, r);
609    }
610
611    /// Count of the table entries
612    pub fn entry_count(&self) -> usize {
613        let mut count = 0usize;
614        self.state.push_nil();
615        while self.state.next(self.index) {
616            count += 1;
617            self.state.pop(1);
618        }
619        count
620    }
621
622    /// Iterator to the table entries
623    pub fn iter<'t>(&'t self) -> Result<TableIter<'l, &'t Self>> {
624        Ok(TableIter {
625            val: self,
626            key: Some(self.state.new_val(())?),
627        })
628    }
629
630    /// Like `iter()`, but take the ownership
631    pub fn into_iter(self) -> Result<TableIter<'l, Self>> {
632        let key = self.state.new_val(())?;
633        Ok(TableIter {
634            val: self,
635            key: Some(key),
636        })
637    }
638
639    /// Get value by number index without metamethod triggers
640    #[inline]
641    pub fn raw_geti(&self, i: impl Into<lua_Integer>) -> Result<ValRef<'l>> {
642        self.state.check_stack(1)?;
643        self.state.raw_geti(self.index, i.into());
644        Ok(self.state.top_val())
645    }
646
647    /// Set value by number index without metamethod triggers
648    #[inline]
649    pub fn raw_seti<V: ToLua>(&self, i: impl Into<lua_Integer>, v: V) -> Result<()> {
650        self.state.check_stack(2)?;
651        self.state.push(v)?;
652        self.state.raw_seti(self.index, i.into());
653        Ok(())
654    }
655
656    pub fn take_reference(&self, r: Reference) -> Result<ValRef<'l>> {
657        let res = self.raw_geti(r.0)?;
658        self.unreference(r);
659        Ok(res)
660    }
661
662    /// Get the value associated to `key` without metamethod triggers
663    #[inline]
664    pub fn raw_get<K: ToLua>(&self, key: K) -> Result<ValRef<'l>> {
665        self.state.check_stack(2)?;
666        self.state.push(key)?;
667        self.state.check_nil_pop()?;
668        self.state.raw_get(self.index);
669        Ok(self.state.top_val())
670    }
671
672    /// Set value by any key without metamethod triggers
673    #[inline]
674    pub fn raw_set<K: ToLua, V: ToLua>(&self, k: K, v: V) -> Result<()> {
675        self.state.check_stack(3)?;
676        self.state.push(k)?;
677        self.state.check_nil_pop()?;
678        self.state.push(v)?;
679        self.state.raw_set(self.index);
680        Ok(())
681    }
682
683    /// Insert an element into the array table, equivalent to `table.insert` in lua
684    #[inline(always)]
685    pub fn raw_insert<V: ToLua>(&self, i: usize, val: V) -> Result<()> {
686        self.raw_move_vals(i)?;
687        self.raw_seti(i as i64, val)
688    }
689
690    #[doc(hidden)]
691    pub fn raw_move_vals(&self, i: usize) -> Result<()> {
692        for i in i..=self.raw_len() {
693            self.raw_seti((i + 1) as i64, self.raw_get(i as i64)?)?;
694        }
695        Ok(())
696    }
697
698    /// Push an element to end of the array part of a table, alias to `self.raw_seti((self.raw_len() + 1) as i64, val)`
699    #[inline(always)]
700    pub fn push<V: ToLua>(&self, val: V) -> Result<()> {
701        self.raw_seti((self.raw_len() + 1) as i64, val)
702    }
703
704    /// Iterator to the table entries
705    #[inline(always)]
706    pub fn pairs(&self) -> Result<impl Iterator<Item = (Value, Value)>> {
707        Ok(self.iter()?.map(|(k, v)| (k.into_value(), v.into_value())))
708    }
709
710    /// Alias to `self.set(name, lua.new_closure(func))`
711    #[inline(always)]
712    pub fn set_closure<'a, K: ToLua, A: 'a, R: 'a, F: LuaMethod<'a, (), A, R> + 'static>(
713        &self,
714        name: K,
715        func: F,
716    ) -> Result<&Self> {
717        self.raw_set(name, self.state.new_closure(func)?)
718            .map(|_| self)
719    }
720
721    /// Alias to `self.set(name, lua.new_function(func))`
722    #[inline(always)]
723    pub fn set_function<
724        'a,
725        K: ToLua,
726        ARGS: FromLuaMulti<'l>,
727        RET: ToLuaMulti + 'l,
728        F: Fn(&'l State, ARGS) -> RET + 'static,
729    >(
730        &self,
731        name: K,
732        func: F,
733    ) -> Result<&Self> {
734        self.raw_set(name, self.state.new_function(func)?)
735            .map(|_| self)
736    }
737}
738
739impl<'a> Function<'a> {
740    #[inline(always)]
741    pub fn get_upvalue(&self, i: Index) -> Result<Option<ValRef<'a>>> {
742        self.get_upvalue_name(i).map(|x| x.map(|x| x.0))
743    }
744
745    #[inline]
746    pub fn get_upvalue_name(&self, i: Index) -> Result<Option<(ValRef<'a>, &'a str)>> {
747        Ok(self
748            .state
749            .get_upvalue(self.index, i)
750            .map(|name| (self.state.top_val(), name)))
751    }
752
753    #[inline(always)]
754    pub fn set_upvalue(&self, i: Index, val: impl ToLua) -> Result<()> {
755        self.state.push(val)?;
756        self.state.set_upvalue(self.index, i);
757        Ok(())
758    }
759
760    pub fn upvalues(&self) -> Result<Vec<ValRef<'a>>> {
761        let mut result = Vec::new();
762        for i in 1.. {
763            let Some(x) = self.get_upvalue(i)? else {
764                break;
765            };
766            result.push(x);
767        }
768        Ok(result)
769    }
770
771    /// Dumps the function as a binary chunk.
772    ///
773    /// If `strip` is true, the binary representation may not include all debug information
774    /// about the function, to save space.
775    pub fn dump(&self, strip: bool) -> Vec<u8> {
776        let mut data: Vec<u8> = Vec::new();
777        self.state.dump(|buf| data.extend_from_slice(buf), strip);
778        data
779    }
780}
781
782impl<'a> AsRef<Table<'a>> for Table<'a> {
783    fn as_ref(&self) -> &Table<'a> {
784        self
785    }
786}
787
788impl<'a> LuaString<'a> {
789    #[inline]
790    pub fn to_string_lossy(&self) -> Cow<str> {
791        self.state.to_string_lossy(self.index).unwrap_or_default()
792    }
793}
794
795impl<'a> LuaUserData<'a> {
796    /// Set uservalue
797    #[inline]
798    pub fn set_uservalue<V: ToLua>(&self, v: V) -> Result<()> {
799        self.check_type(Type::Userdata)?;
800        self.state.push(v)?;
801        self.state.set_uservalue(self.index);
802        Ok(())
803    }
804
805    /// Get the uservalue stored in uservalue
806    #[inline]
807    pub fn get_uservalue(&self) -> Result<ValRef<'a>> {
808        self.check_type(Type::Userdata)?;
809        self.state.get_uservalue(self.index);
810        Ok(self.state.top_val())
811    }
812
813    /// Set n-th uservalue
814    #[inline]
815    pub fn set_iuservalue<V: ToLua>(&self, n: i32, v: V) -> Result<()> {
816        self.check_type(Type::Userdata)?;
817        self.state.push(v)?;
818        self.state.set_iuservalue(self.index, n);
819        Ok(())
820    }
821
822    /// Get n-th uservalue stored in uservalue
823    #[inline]
824    pub fn get_iuservalue(&self, n: i32) -> Result<ValRef<'a>> {
825        self.check_type(Type::Userdata)?;
826        self.state.get_iuservalue(self.index, n);
827        Ok(self.state.top_val())
828    }
829
830    pub fn uservalues(&self) -> Result<Vec<ValRef>> {
831        self.check_type(Type::Userdata)?;
832        let mut result = Vec::new();
833        while self.state.get_uservalue(self.index) != Type::None {
834            result.push(self.state.top_val());
835        }
836        Ok(result)
837    }
838
839    /// Take the ownership, and subsequent access in lua is invalid
840    pub fn take<U: UserData>(self) -> Option<U::Trans> {
841        unsafe {
842            self.userdata_ref::<U>().map(|p| {
843                self.remove_metatable();
844                core::ptr::read(p)
845            })
846        }
847    }
848
849    pub fn userdata_pointer(&self) -> *mut c_void {
850        self.state.to_userdata(self.index)
851    }
852
853    pub unsafe fn userdata_bytes(&self) -> &[u8] {
854        core::slice::from_raw_parts(self.userdata_pointer().cast::<u8>(), self.raw_len())
855    }
856
857    pub unsafe fn get_ref_unchecked<U: UserData>(&self) -> Option<&mut U::Trans> {
858        self.state
859            .to_userdata(self.index)
860            .cast::<U::Trans>()
861            .as_mut()
862    }
863
864    pub fn userdata_ref<U: UserData>(&self) -> Option<&U::Trans> {
865        unsafe {
866            self.state
867                .test_userdata_meta::<U::Trans>(self.index, U::metatable_key())
868                .map(|x| x as _)
869        }
870    }
871
872    pub unsafe fn userdata_ref_mut<U: UserData>(&self) -> Option<&mut U::Trans> {
873        self.state
874            .test_userdata_meta::<U::Trans>(self.index, U::metatable_key())
875    }
876}
877
878macro_rules! protect_airth {
879    ($op:expr) => {{
880        unsafe extern "C-unwind" fn protect(l: *mut ffi::lua_State) -> i32 {
881            ffi::lua_arith(l, $op);
882            1
883        }
884        protect
885    }};
886}
887
888macro_rules! impl_binop {
889    ($t:ident, $trait:ty, $name:ident, $method:ident, $op:expr) => {
890        #[inline]
891        pub fn $method(&self, rhs: impl ToLua) -> Result<Self> {
892            impl<'l, $t: ToLua> $trait for &ValRef<'l> {
893                type Output = Result<ValRef<'l>>;
894
895                fn $name(self, rhs: T) -> Self::Output {
896                    self.$method(rhs)
897                }
898            }
899
900            impl<'l, $t: ToLua> $trait for ValRef<'l> {
901                type Output = Result<ValRef<'l>>;
902
903                fn $name(self, rhs: T) -> Self::Output {
904                    self.$method(rhs)
905                }
906            }
907
908            self.state.protect_call((self, rhs), protect_airth!($op))
909        }
910    };
911}
912
913macro_rules! impl_op {
914    ($trait:ty, $name:ident, $method:ident, $op:expr) => {
915        #[inline]
916        pub fn $method(&self) -> Result<Self> {
917            impl<'l> $trait for &ValRef<'l> {
918                type Output = Result<ValRef<'l>>;
919
920                fn $name(self) -> Self::Output {
921                    self.$method()
922                }
923            }
924
925            impl<'l> $trait for ValRef<'l> {
926                type Output = Result<ValRef<'l>>;
927
928                fn $name(self) -> Self::Output {
929                    self.$method()
930                }
931            }
932
933            self.state.protect_call(self, protect_airth!($op))
934        }
935    };
936}
937
938impl ValRef<'_> {
939    impl_binop!(T, ops::Add<T>, add, airth_add, ffi::LUA_OPADD);
940    impl_binop!(T, ops::Sub<T>, sub, airth_sub, ffi::LUA_OPSUB);
941    impl_binop!(T, ops::Mul<T>, mul, airth_mul, ffi::LUA_OPMUL);
942    impl_binop!(T, ops::Div<T>, div, airth_div, ffi::LUA_OPDIV);
943    impl_binop!(T, ops::Rem<T>, rem, airth_rem, ffi::LUA_OPMOD);
944    impl_binop!(T, ops::BitAnd<T>, bitand, airth_bitand, ffi::LUA_OPBAND);
945    impl_binop!(T, ops::BitOr<T>, bitor, airth_bitor, ffi::LUA_OPBOR);
946    impl_binop!(T, ops::BitXor<T>, bitxor, airth_bitxor, ffi::LUA_OPBXOR);
947    impl_binop!(T, ops::Shl<T>, shl, airth_shl, ffi::LUA_OPSHL);
948    impl_binop!(T, ops::Shr<T>, shr, airth_shr, ffi::LUA_OPSHR);
949
950    impl_op!(ops::Neg, neg, arith_neg, ffi::LUA_OPUNM);
951    impl_op!(ops::Not, not, arith_not, ffi::LUA_OPBNOT);
952
953    pub fn idiv(&self, rhs: impl ToLua) -> Result<Self> {
954        self.state
955            .protect_call((self, rhs), protect_airth!(ffi::LUA_OPIDIV))
956    }
957
958    pub fn pow(&self, rhs: impl ToLua) -> Result<Self> {
959        self.state
960            .protect_call((self, rhs), protect_airth!(ffi::LUA_OPPOW))
961    }
962}
963
964macro_rules! protect_compare {
965    ($op:expr) => {{
966        unsafe extern "C-unwind" fn protect(l: *mut ffi::lua_State) -> i32 {
967            ffi::lua_pushboolean(l, ffi::lua_compare(l, 1, 2, $op));
968            1
969        }
970        protect
971    }};
972}
973
974impl PartialEq for ValRef<'_> {
975    fn eq(&self, other: &Self) -> bool {
976        self.state
977            .protect_call((self, other), protect_compare!(ffi::LUA_OPEQ))
978            .unwrap_or_default()
979    }
980}