1use 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
19pub 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 #[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 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 #[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 #[inline(always)]
190 pub fn cast_into<T: FromLua<'a> + 'a>(self) -> Result<T> {
191 FromLua::from_lua(self.state, self)
192 }
193
194 #[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 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 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 #[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 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 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 #[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 #[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 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 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 pub fn remove_metatable(&self) {
341 self.state.check_stack(1).expect("check");
342 self.state.push_nil();
344 self.state.set_metatable(self.index);
345 }
346
347 #[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 #[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 pub fn raw_equal(&self, other: &Self) -> bool {
373 self.state.raw_equal(self.index, other.index)
374 }
375
376 #[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 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 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
448pub 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#[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#[derive(Debug, Clone, derive_more::Deref)]
506pub struct Table<'l>(pub(crate) ValRef<'l>);
507
508#[derive(Debug, Clone, derive_more::Deref)]
510pub struct Function<'l>(pub(crate) ValRef<'l>);
511
512#[derive(Debug, Clone, derive_more::Deref)]
514pub struct LuaString<'l>(pub(crate) ValRef<'l>);
515
516#[derive(Debug, Clone, derive_more::Deref)]
518pub struct LuaThread<'l>(pub(crate) ValRef<'l>);
519
520#[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> 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 #[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 #[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 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 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 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 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 #[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 #[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 #[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 #[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 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}