1use std::collections::HashSet;
155use std::fmt;
156use std::marker::PhantomData;
157use std::os::raw::c_void;
158
159use crate::error::{Error, Result};
160use crate::function::Function;
161use crate::state::{LuaGuard, RawLua, WeakLua};
162use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, ObjectLike};
163use crate::types::{Integer, ValueRef};
164use crate::util::{StackGuard, assert_stack, check_stack, get_metatable_ptr};
165use crate::value::{Nil, Value};
166
167#[cfg(feature = "async")]
168use crate::function::AsyncCallFuture;
169
170#[cfg(feature = "serde")]
171use {
172 rustc_hash::FxHashSet,
173 serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer},
174 std::{cell::RefCell, rc::Rc, result::Result as StdResult},
175};
176
177#[derive(Clone, PartialEq)]
179pub struct Table(pub(crate) ValueRef);
180
181impl Table {
182 pub fn set(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
216 if !self.has_metatable() {
218 return self.raw_set(key, value);
219 }
220
221 self.set_protected(key, value)
222 }
223
224 pub(crate) fn set_protected(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
225 let lua = self.0.lua.lock();
226 let state = lua.state();
227 unsafe {
228 let _sg = StackGuard::new(state);
229 check_stack(state, 5)?;
230
231 lua.push_ref(&self.0);
232 key.push_into_stack(&lua)?;
233 value.push_into_stack(&lua)?;
234 protect_lua!(state, 3, 0, fn(state) ffi::lua_settable(state, -3))
235 }
236 }
237
238 pub fn get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
263 if !self.has_metatable() {
265 return self.raw_get(key);
266 }
267
268 self.get_protected(key)
269 }
270
271 pub(crate) fn get_protected<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
272 let lua = self.0.lua.lock();
273 let state = lua.state();
274 unsafe {
275 let _sg = StackGuard::new(state);
276 check_stack(state, 4)?;
277
278 lua.push_ref(&self.0);
279 key.push_into_stack(&lua)?;
280 protect_lua!(state, 2, 1, fn(state) ffi::lua_gettable(state, -2))?;
281
282 V::from_stack(-1, &lua)
283 }
284 }
285
286 pub fn contains_key(&self, key: impl IntoLua) -> Result<bool> {
290 Ok(self.get::<Value>(key)? != Value::Nil)
291 }
292
293 pub fn push(&self, value: impl IntoLua) -> Result<()> {
297 if !self.has_metatable() {
299 return self.raw_push(value);
300 }
301
302 let lua = self.0.lua.lock();
303 let state = lua.state();
304 unsafe {
305 let _sg = StackGuard::new(state);
306 check_stack(state, 4)?;
307
308 lua.push_ref(&self.0);
309 value.push_into_stack(&lua)?;
310 protect_lua!(state, 2, 0, fn(state) {
311 let len = ffi::luaL_len(state, -2) as Integer;
312 ffi::lua_seti(state, -2, len + 1);
313 })?
314 }
315 Ok(())
316 }
317
318 pub fn pop<V: FromLua>(&self) -> Result<V> {
322 if !self.has_metatable() {
324 return self.raw_pop();
325 }
326
327 let lua = self.0.lua.lock();
328 let state = lua.state();
329 unsafe {
330 let _sg = StackGuard::new(state);
331 check_stack(state, 4)?;
332
333 lua.push_ref(&self.0);
334 protect_lua!(state, 1, 1, fn(state) {
335 let len = ffi::luaL_len(state, -1) as Integer;
336 ffi::lua_geti(state, -1, len);
337 ffi::lua_pushnil(state);
338 ffi::lua_seti(state, -3, len);
339 })?;
340 V::from_stack(-1, &lua)
341 }
342 }
343
344 pub fn remove(&self, key: impl IntoLua) -> Result<()> {
357 if !self.has_metatable() {
359 return self.raw_remove(key);
360 }
361
362 let lua = self.0.lua.lock();
363 let key = key.into_lua(lua.lua())?;
364 match key {
365 Value::Integer(idx) => {
366 let size = self.len()?;
367 if idx < 1 || idx > size {
368 return Err(Error::runtime("index out of bounds"));
369 }
370
371 let state = lua.state();
372 unsafe {
373 let _sg = StackGuard::new(state);
374 check_stack(state, 4)?;
375
376 lua.push_ref(&self.0);
377 protect_lua!(state, 1, 0, |state| {
378 for i in idx..size {
379 ffi::lua_geti(state, -1, i + 1);
381 ffi::lua_seti(state, -2, i);
382 }
383 ffi::lua_pushnil(state);
384 ffi::lua_seti(state, -2, size);
385 })
386 }
387 }
388 _ => self.set(key, Nil),
389 }
390 }
391
392 pub fn equals(&self, other: &Self) -> Result<bool> {
422 if self == other {
423 return Ok(true);
424 }
425
426 if let Some(mt) = self.metatable()
430 && let Some(eq_func) = mt.get::<Option<Function>>("__eq")?
431 {
432 return eq_func.call((self, other));
433 }
434 if let Some(mt) = other.metatable()
435 && let Some(eq_func) = mt.get::<Option<Function>>("__eq")?
436 {
437 return eq_func.call((self, other));
438 }
439
440 Ok(false)
441 }
442
443 pub fn raw_set(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
445 let lua = self.0.lua.lock();
446 let state = lua.state();
447 unsafe {
448 #[cfg(feature = "luau")]
449 self.check_readonly_write(&lua)?;
450
451 let _sg = StackGuard::new(state);
452 check_stack(state, 5)?;
453
454 lua.push_ref(&self.0);
455 key.push_into_stack(&lua)?;
456 value.push_into_stack(&lua)?;
457
458 if lua.unlikely_memory_error() {
459 ffi::lua_rawset(state, -3);
460 ffi::lua_pop(state, 1);
461 Ok(())
462 } else {
463 protect_lua!(state, 3, 0, fn(state) ffi::lua_rawset(state, -3))
464 }
465 }
466 }
467
468 pub fn raw_get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
470 let lua = self.0.lua.lock();
471 let state = lua.state();
472 unsafe {
473 let _sg = StackGuard::new(state);
474 check_stack(state, 3)?;
475
476 lua.push_ref(&self.0);
477 key.push_into_stack(&lua)?;
478 ffi::lua_rawget(state, -2);
479
480 V::from_stack(-1, &lua)
481 }
482 }
483
484 pub fn raw_insert(&self, idx: Integer, value: impl IntoLua) -> Result<()> {
489 let size = self.raw_len() as Integer;
490 if idx < 1 || idx > size + 1 {
491 return Err(Error::runtime("index out of bounds"));
492 }
493
494 let lua = self.0.lua.lock();
495 let state = lua.state();
496 unsafe {
497 let _sg = StackGuard::new(state);
498 check_stack(state, 5)?;
499
500 lua.push_ref(&self.0);
501 value.push_into_stack(&lua)?;
502 protect_lua!(state, 2, 0, |state| {
503 for i in (idx..=size).rev() {
504 ffi::lua_rawgeti(state, -2, i);
506 ffi::lua_rawseti(state, -3, i + 1);
507 }
508 ffi::lua_rawseti(state, -2, idx)
509 })
510 }
511 }
512
513 pub fn raw_push(&self, value: impl IntoLua) -> Result<()> {
515 let lua = self.0.lua.lock();
516 let state = lua.state();
517 unsafe {
518 #[cfg(feature = "luau")]
519 self.check_readonly_write(&lua)?;
520
521 let _sg = StackGuard::new(state);
522 check_stack(state, 4)?;
523
524 lua.push_ref(&self.0);
525 value.push_into_stack(&lua)?;
526
527 unsafe fn callback(state: *mut ffi::lua_State) {
528 let len = ffi::lua_rawlen(state, -2) as Integer;
529 ffi::lua_rawseti(state, -2, len + 1);
530 }
531
532 if lua.unlikely_memory_error() {
533 callback(state);
534 } else {
535 protect_lua!(state, 2, 0, fn(state) callback(state))?;
536 }
537 }
538 Ok(())
539 }
540
541 pub fn raw_pop<V: FromLua>(&self) -> Result<V> {
543 let lua = self.0.lua.lock();
544 let state = lua.state();
545 unsafe {
546 #[cfg(feature = "luau")]
547 self.check_readonly_write(&lua)?;
548
549 let _sg = StackGuard::new(state);
550 check_stack(state, 3)?;
551
552 lua.push_ref(&self.0);
553 let len = ffi::lua_rawlen(state, -1) as Integer;
554 ffi::lua_rawgeti(state, -1, len);
555 ffi::lua_pushnil(state);
557 ffi::lua_rawseti(state, -3, len);
558
559 V::from_stack(-1, &lua)
560 }
561 }
562
563 pub fn raw_remove(&self, key: impl IntoLua) -> Result<()> {
571 let lua = self.0.lua.lock();
572 let state = lua.state();
573 let key = key.into_lua(lua.lua())?;
574 match key {
575 Value::Integer(idx) => {
576 let size = self.raw_len() as Integer;
577 if idx < 1 || idx > size {
578 return Err(Error::runtime("index out of bounds"));
579 }
580 unsafe {
581 let _sg = StackGuard::new(state);
582 check_stack(state, 4)?;
583
584 lua.push_ref(&self.0);
585 protect_lua!(state, 1, 0, |state| {
586 for i in idx..size {
587 ffi::lua_rawgeti(state, -1, i + 1);
588 ffi::lua_rawseti(state, -2, i);
589 }
590 ffi::lua_pushnil(state);
591 ffi::lua_rawseti(state, -2, size);
592 })
593 }
594 }
595 _ => self.raw_set(key, Nil),
596 }
597 }
598
599 pub fn clear(&self) -> Result<()> {
604 let lua = self.0.lua.lock();
605 unsafe {
606 #[cfg(feature = "luau")]
607 {
608 self.check_readonly_write(&lua)?;
609 ffi::lua_cleartable(lua.ref_thread(), self.0.index);
610 }
611
612 #[cfg(not(feature = "luau"))]
613 {
614 let state = lua.state();
615 let _sg = StackGuard::new(state);
616 check_stack(state, 4)?;
617
618 lua.push_ref(&self.0);
619
620 ffi::lua_pushnil(state);
622 while ffi::lua_next(state, -2) != 0 {
623 ffi::lua_pop(state, 1); ffi::lua_pushvalue(state, -1); ffi::lua_pushnil(state);
626 ffi::lua_rawset(state, -4);
627 }
628 }
629 }
630
631 Ok(())
632 }
633
634 pub fn len(&self) -> Result<Integer> {
639 if !self.has_metatable() {
641 return Ok(self.raw_len() as Integer);
642 }
643
644 let lua = self.0.lua.lock();
645 let state = lua.state();
646 unsafe {
647 let _sg = StackGuard::new(state);
648 check_stack(state, 4)?;
649
650 lua.push_ref(&self.0);
651 protect_lua!(state, 1, 0, |state| ffi::luaL_len(state, -1))
652 }
653 }
654
655 pub fn raw_len(&self) -> usize {
657 let lua = self.0.lua.lock();
658 unsafe { ffi::lua_rawlen(lua.ref_thread(), self.0.index) }
659 }
660
661 pub fn is_empty(&self) -> bool {
665 let lua = self.0.lua.lock();
666 let ref_thread = lua.ref_thread();
667 unsafe {
668 ffi::lua_pushnil(ref_thread);
669 if ffi::lua_next(ref_thread, self.0.index) == 0 {
670 return true;
671 }
672 ffi::lua_pop(ref_thread, 2);
673 }
674 false
675 }
676
677 pub fn metatable(&self) -> Option<Table> {
683 let lua = self.0.lua.lock();
684 let ref_thread = lua.ref_thread();
685 unsafe {
686 if ffi::lua_getmetatable(ref_thread, self.0.index) == 0 {
687 None
688 } else {
689 Some(Table(lua.pop_ref_thread()))
690 }
691 }
692 }
693
694 pub fn set_metatable(&self, metatable: Option<Table>) -> Result<()> {
699 #[cfg(feature = "luau")]
700 if self.is_readonly() {
701 return Err(Error::runtime("attempt to modify a readonly table"));
702 }
703
704 let lua = self.0.lua.lock();
705 let ref_thread = lua.ref_thread();
706 unsafe {
707 if let Some(metatable) = &metatable {
708 ffi::lua_pushvalue(ref_thread, metatable.0.index);
709 } else {
710 ffi::lua_pushnil(ref_thread);
711 }
712 ffi::lua_setmetatable(ref_thread, self.0.index);
713 }
714 Ok(())
715 }
716
717 #[doc(hidden)]
719 #[inline]
720 pub fn has_metatable(&self) -> bool {
721 let lua = self.0.lua.lock();
722 unsafe { !get_metatable_ptr(lua.ref_thread(), self.0.index).is_null() }
723 }
724
725 #[cfg(any(feature = "luau", doc))]
727 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
728 pub fn set_readonly(&self, enabled: bool) {
729 let lua = self.0.lua.lock();
730 let ref_thread = lua.ref_thread();
731 unsafe {
732 ffi::lua_setreadonly(ref_thread, self.0.index, enabled as _);
733 if !enabled {
734 ffi::lua_setsafeenv(ref_thread, self.0.index, 0);
736 }
737 }
738 }
739
740 #[cfg(any(feature = "luau", doc))]
742 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
743 pub fn is_readonly(&self) -> bool {
744 let lua = self.0.lua.lock();
745 let ref_thread = lua.ref_thread();
746 unsafe { ffi::lua_getreadonly(ref_thread, self.0.index) != 0 }
747 }
748
749 #[cfg(any(feature = "luau", doc))]
759 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
760 pub fn set_safeenv(&self, enabled: bool) {
761 let lua = self.0.lua.lock();
762 unsafe { ffi::lua_setsafeenv(lua.ref_thread(), self.0.index, enabled as _) };
763 }
764
765 #[inline]
772 pub fn to_pointer(&self) -> *const c_void {
773 self.0.to_pointer()
774 }
775
776 pub fn pairs<K: FromLua, V: FromLua>(&self) -> TablePairs<'_, K, V> {
803 TablePairs {
804 guard: self.0.lua.lock(),
805 table: self,
806 key: Some(Nil),
807 _phantom: PhantomData,
808 }
809 }
810
811 pub fn for_each<K, V>(&self, mut f: impl FnMut(K, V) -> Result<()>) -> Result<()>
816 where
817 K: FromLua,
818 V: FromLua,
819 {
820 let lua = self.0.lua.lock();
821 let state = lua.state();
822 unsafe {
823 let _sg = StackGuard::new(state);
824 check_stack(state, 5)?;
825
826 lua.push_ref(&self.0);
827 ffi::lua_pushnil(state);
828 while ffi::lua_next(state, -2) != 0 {
829 let k = K::from_stack(-2, &lua)?;
830 let v = lua.pop::<V>()?;
831 f(k, v)?;
832 }
833 }
834 Ok(())
835 }
836
837 pub fn sequence_values<V: FromLua>(&self) -> TableSequence<'_, V> {
866 TableSequence {
867 guard: self.0.lua.lock(),
868 table: self,
869 index: 1,
870 len: None,
871 _phantom: PhantomData,
872 }
873 }
874
875 #[doc(hidden)]
879 pub fn for_each_value<V: FromLua>(&self, f: impl FnMut(V) -> Result<()>) -> Result<()> {
880 self.for_each_value_by_len(None, f)
881 }
882
883 fn for_each_value_by_len<V: FromLua>(
884 &self,
885 len: impl Into<Option<usize>>,
886 mut f: impl FnMut(V) -> Result<()>,
887 ) -> Result<()> {
888 let len = len.into();
889 let lua = self.0.lua.lock();
890 let state = lua.state();
891 unsafe {
892 let _sg = StackGuard::new(state);
893 check_stack(state, 4)?;
894
895 lua.push_ref(&self.0);
896 for i in 1.. {
897 if len.map(|len| i > len).unwrap_or(false) {
898 break;
899 }
900 let t = ffi::lua_rawgeti(state, -1, i as _);
901 if len.is_none() && t == ffi::LUA_TNIL {
902 break;
903 }
904 f(lua.pop::<V>()?)?;
905 }
906 }
907 Ok(())
908 }
909
910 #[doc(hidden)]
912 pub fn raw_seti(&self, idx: usize, value: impl IntoLua) -> Result<()> {
913 let lua = self.0.lua.lock();
914 let state = lua.state();
915 unsafe {
916 #[cfg(feature = "luau")]
917 self.check_readonly_write(&lua)?;
918
919 let _sg = StackGuard::new(state);
920 check_stack(state, 5)?;
921
922 lua.push_ref(&self.0);
923 value.push_into_stack(&lua)?;
924
925 let idx = idx.try_into().unwrap();
926 if lua.unlikely_memory_error() {
927 ffi::lua_rawseti(state, -2, idx);
928 } else {
929 protect_lua!(state, 2, 0, |state| ffi::lua_rawseti(state, -2, idx))?;
930 }
931 }
932 Ok(())
933 }
934
935 #[cfg(feature = "serde")]
937 fn has_array_metatable(&self) -> bool {
938 let lua = self.0.lua.lock();
939 let state = lua.state();
940 unsafe {
941 let _sg = StackGuard::new(state);
942 assert_stack(state, 3);
943
944 lua.push_ref(&self.0);
945 if ffi::lua_getmetatable(state, -1) == 0 {
946 return false;
947 }
948 crate::serde::push_array_metatable(state);
949 ffi::lua_rawequal(state, -1, -2) != 0
950 }
951 }
952
953 #[cfg(feature = "serde")]
959 fn find_array_len(&self) -> Option<(usize, usize)> {
960 let lua = self.0.lua.lock();
961 let ref_thread = lua.ref_thread();
962 unsafe {
963 let _sg = StackGuard::new(ref_thread);
964
965 let (mut count, mut max_index) = (0, 0);
966 ffi::lua_pushnil(ref_thread);
967 while ffi::lua_next(ref_thread, self.0.index) != 0 {
968 if ffi::lua_type(ref_thread, -2) != ffi::LUA_TNUMBER {
969 return None;
970 }
971
972 let k = ffi::lua_tonumber(ref_thread, -2);
973 if k.trunc() != k || k < 1.0 {
974 return None;
975 }
976 max_index = std::cmp::max(max_index, k as usize);
977 count += 1;
978 ffi::lua_pop(ref_thread, 1);
979 }
980 Some((count, max_index))
981 }
982 }
983
984 #[cfg(feature = "serde")]
999 pub(crate) fn encode_as_array(&self, options: crate::serde::de::Options) -> Option<usize> {
1000 if self.has_array_metatable() {
1001 return Some(self.raw_len());
1002 }
1003 if options.detect_mixed_tables {
1004 if let Some((len, max_idx)) = self.find_array_len() {
1005 if len < 10 || len * 2 >= max_idx {
1007 return Some(max_idx);
1008 }
1009 }
1010 } else {
1011 let len = self.raw_len();
1012 if len > 0 {
1013 return Some(len);
1014 }
1015 if options.encode_empty_tables_as_array && self.is_empty() {
1016 return Some(0);
1017 }
1018 }
1019 None
1020 }
1021
1022 #[cfg(feature = "luau")]
1023 #[inline(always)]
1024 fn check_readonly_write(&self, lua: &RawLua) -> Result<()> {
1025 if unsafe { ffi::lua_getreadonly(lua.ref_thread(), self.0.index) != 0 } {
1026 return Err(Error::runtime("attempt to modify a readonly table"));
1027 }
1028 Ok(())
1029 }
1030
1031 pub(crate) fn fmt_pretty(
1032 &self,
1033 fmt: &mut fmt::Formatter,
1034 ident: usize,
1035 visited: &mut HashSet<*const c_void>,
1036 ) -> fmt::Result {
1037 visited.insert(self.to_pointer());
1038
1039 let mut pairs = self.pairs::<Value, Value>().flatten().collect::<Vec<_>>();
1041 pairs.sort_by(|(a, _), (b, _)| a.sort_cmp(b));
1043 let is_sequence = (pairs.iter().enumerate())
1044 .all(|(i, (k, _))| matches!(k, Value::Integer(n) if *n == (i + 1) as Integer));
1045 if pairs.is_empty() {
1046 return write!(fmt, "{{}}");
1047 }
1048 writeln!(fmt, "{{")?;
1049 if is_sequence {
1050 for (_, value) in pairs {
1052 write!(fmt, "{}", " ".repeat(ident + 2))?;
1053 value.fmt_pretty(fmt, true, ident + 2, visited)?;
1054 writeln!(fmt, ",")?;
1055 }
1056 } else {
1057 fn is_simple_key(key: &[u8]) -> bool {
1058 key.iter().take(1).all(|c| c.is_ascii_alphabetic() || *c == b'_')
1059 && key.iter().all(|c| c.is_ascii_alphanumeric() || *c == b'_')
1060 }
1061
1062 for (key, value) in pairs {
1063 match key {
1064 Value::String(key) if is_simple_key(&key.as_bytes()) => {
1065 write!(fmt, "{}{}", " ".repeat(ident + 2), key.display())?;
1066 write!(fmt, " = ")?;
1067 }
1068 _ => {
1069 write!(fmt, "{}[", " ".repeat(ident + 2))?;
1070 key.fmt_pretty(fmt, false, ident + 2, visited)?;
1071 write!(fmt, "] = ")?;
1072 }
1073 }
1074 value.fmt_pretty(fmt, true, ident + 2, visited)?;
1075 writeln!(fmt, ",")?;
1076 }
1077 }
1078 write!(fmt, "{}}}", " ".repeat(ident))
1079 }
1080}
1081
1082impl fmt::Debug for Table {
1083 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1084 if fmt.alternate() {
1085 return self.fmt_pretty(fmt, 0, &mut HashSet::new());
1086 }
1087 fmt.debug_tuple("Table").field(&self.0).finish()
1088 }
1089}
1090
1091impl<T> PartialEq<[T]> for Table
1092where
1093 T: IntoLua + Clone,
1094{
1095 fn eq(&self, other: &[T]) -> bool {
1096 let lua = self.0.lua.lock();
1097 let state = lua.state();
1098 unsafe {
1099 let _sg = StackGuard::new(state);
1100 assert_stack(state, 4);
1101
1102 lua.push_ref(&self.0);
1103
1104 let len = ffi::lua_rawlen(state, -1);
1105 for i in 0..len {
1106 ffi::lua_rawgeti(state, -1, (i + 1) as _);
1107 let val = lua.pop_value();
1108 if val == Nil {
1109 return i == other.len();
1110 }
1111 match other.get(i).map(|v| v.clone().into_lua(lua.lua())) {
1112 Some(Ok(other_val)) if val == other_val => continue,
1113 _ => return false,
1114 }
1115 }
1116 }
1117 true
1118 }
1119}
1120
1121impl<T> PartialEq<&[T]> for Table
1122where
1123 T: IntoLua + Clone,
1124{
1125 #[inline]
1126 fn eq(&self, other: &&[T]) -> bool {
1127 self == *other
1128 }
1129}
1130
1131impl<T, const N: usize> PartialEq<[T; N]> for Table
1132where
1133 T: IntoLua + Clone,
1134{
1135 #[inline]
1136 fn eq(&self, other: &[T; N]) -> bool {
1137 self == &other[..]
1138 }
1139}
1140
1141impl ObjectLike for Table {
1142 #[inline]
1143 fn get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
1144 self.get(key)
1145 }
1146
1147 #[inline]
1148 fn set(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
1149 self.set(key, value)
1150 }
1151
1152 #[inline]
1153 fn call<R>(&self, args: impl IntoLuaMulti) -> Result<R>
1154 where
1155 R: FromLuaMulti,
1156 {
1157 Function(self.0.clone()).call(args)
1159 }
1160
1161 #[cfg(feature = "async")]
1162 #[inline]
1163 fn call_async<R>(&self, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
1164 where
1165 R: FromLuaMulti,
1166 {
1167 Function(self.0.clone()).call_async(args)
1168 }
1169
1170 #[inline]
1171 fn call_method<R>(&self, name: &str, args: impl IntoLuaMulti) -> Result<R>
1172 where
1173 R: FromLuaMulti,
1174 {
1175 self.call_function(name, (self, args))
1176 }
1177
1178 #[cfg(feature = "async")]
1179 fn call_async_method<R>(&self, name: &str, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
1180 where
1181 R: FromLuaMulti,
1182 {
1183 self.call_async_function(name, (self, args))
1184 }
1185
1186 #[inline]
1187 fn call_function<R: FromLuaMulti>(&self, name: &str, args: impl IntoLuaMulti) -> Result<R> {
1188 match self.get(name)? {
1189 Value::Function(func) => func.call(args),
1190 val => {
1191 let msg = format!("attempt to call a {} value (function '{name}')", val.type_name());
1192 Err(Error::runtime(msg))
1193 }
1194 }
1195 }
1196
1197 #[cfg(feature = "async")]
1198 #[inline]
1199 fn call_async_function<R>(&self, name: &str, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
1200 where
1201 R: FromLuaMulti,
1202 {
1203 match self.get(name) {
1204 Ok(Value::Function(func)) => func.call_async(args),
1205 Ok(val) => {
1206 let msg = format!("attempt to call a {} value (function '{name}')", val.type_name());
1207 AsyncCallFuture::error(Error::RuntimeError(msg))
1208 }
1209 Err(err) => AsyncCallFuture::error(err),
1210 }
1211 }
1212
1213 #[inline]
1214 fn to_string(&self) -> Result<String> {
1215 Value::Table(Table(self.0.clone())).to_string()
1216 }
1217
1218 #[inline]
1219 fn to_value(&self) -> Value {
1220 Value::Table(self.clone())
1221 }
1222
1223 #[inline]
1224 fn weak_lua(&self) -> &WeakLua {
1225 &self.0.lua
1226 }
1227}
1228
1229#[cfg(feature = "serde")]
1231pub(crate) struct SerializableTable<'a> {
1232 table: &'a Table,
1233 options: crate::serde::de::Options,
1234 visited: Rc<RefCell<FxHashSet<*const c_void>>>,
1235}
1236
1237#[cfg(feature = "serde")]
1238impl Serialize for Table {
1239 #[inline]
1240 fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
1241 SerializableTable::new(self, Default::default(), Default::default()).serialize(serializer)
1242 }
1243}
1244
1245#[cfg(feature = "serde")]
1246impl<'a> SerializableTable<'a> {
1247 #[inline]
1248 pub(crate) fn new(
1249 table: &'a Table,
1250 options: crate::serde::de::Options,
1251 visited: Rc<RefCell<FxHashSet<*const c_void>>>,
1252 ) -> Self {
1253 Self {
1254 table,
1255 options,
1256 visited,
1257 }
1258 }
1259}
1260
1261impl<V> TableSequence<'_, V> {
1262 #[cfg(feature = "serde")]
1264 pub(crate) fn with_len(mut self, len: usize) -> Self {
1265 self.len = Some(len);
1266 self
1267 }
1268}
1269
1270#[cfg(feature = "serde")]
1271impl Serialize for SerializableTable<'_> {
1272 fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
1273 where
1274 S: Serializer,
1275 {
1276 use crate::serde::de::{MapPairs, RecursionGuard, check_value_for_skip};
1277 use crate::value::SerializableValue;
1278
1279 let convert_result = |res: Result<()>, serialize_err: Option<S::Error>| match res {
1280 Ok(v) => Ok(v),
1281 Err(Error::SerializeError(_)) if serialize_err.is_some() => Err(serialize_err.unwrap()),
1282 Err(Error::SerializeError(msg)) => Err(serde::ser::Error::custom(msg)),
1283 Err(err) => Err(serde::ser::Error::custom(err.to_string())),
1284 };
1285
1286 let options = self.options;
1287 let visited = &self.visited;
1288 let _guard = RecursionGuard::new(self.table, visited);
1289
1290 if let Some(len) = self.table.encode_as_array(self.options) {
1292 let mut seq = serializer.serialize_seq(Some(len))?;
1293 let mut serialize_err = None;
1294 let res = self.table.for_each_value_by_len::<Value>(len, |value| {
1295 let skip = check_value_for_skip(&value, self.options, visited)
1296 .map_err(|err| Error::SerializeError(err.to_string()))?;
1297 if skip {
1298 return Ok(());
1300 }
1301 seq.serialize_element(&SerializableValue::new(&value, options, Some(visited)))
1302 .map_err(|err| {
1303 serialize_err = Some(err);
1304 Error::SerializeError(String::new())
1305 })
1306 });
1307 convert_result(res, serialize_err)?;
1308 return seq.end();
1309 }
1310
1311 let mut map = serializer.serialize_map(None)?;
1313 let mut serialize_err = None;
1314 let mut process_pair = |key, value| {
1315 let skip_key = check_value_for_skip(&key, self.options, visited)
1316 .map_err(|err| Error::SerializeError(err.to_string()))?;
1317 let skip_value = check_value_for_skip(&value, self.options, visited)
1318 .map_err(|err| Error::SerializeError(err.to_string()))?;
1319 if skip_key || skip_value {
1320 return Ok(());
1322 }
1323 map.serialize_entry(
1324 &SerializableValue::new(&key, options, Some(visited)),
1325 &SerializableValue::new(&value, options, Some(visited)),
1326 )
1327 .map_err(|err| {
1328 serialize_err = Some(err);
1329 Error::SerializeError(String::new())
1330 })
1331 };
1332
1333 let res = if !self.options.sort_keys {
1334 self.table.for_each(process_pair)
1336 } else {
1337 MapPairs::new(self.table, self.options.sort_keys)
1338 .map_err(serde::ser::Error::custom)?
1339 .try_for_each(|kv| {
1340 let (key, value) = kv?;
1341 process_pair(key, value)
1342 })
1343 };
1344 convert_result(res, serialize_err)?;
1345 map.end()
1346 }
1347}
1348
1349pub struct TablePairs<'a, K, V> {
1355 guard: LuaGuard,
1356 table: &'a Table,
1357 key: Option<Value>,
1358 _phantom: PhantomData<(K, V)>,
1359}
1360
1361impl<K, V> Iterator for TablePairs<'_, K, V>
1362where
1363 K: FromLua,
1364 V: FromLua,
1365{
1366 type Item = Result<(K, V)>;
1367
1368 fn next(&mut self) -> Option<Self::Item> {
1369 if let Some(prev_key) = self.key.take() {
1370 let lua: &RawLua = &self.guard;
1371 let state = lua.state();
1372
1373 let res = (|| unsafe {
1374 let _sg = StackGuard::new(state);
1375 check_stack(state, 5)?;
1376
1377 lua.push_ref(&self.table.0);
1378 lua.push_value(&prev_key)?;
1379
1380 if ffi::lua_next(state, -2) != 0 {
1384 let key = lua.stack_value(-2, None);
1385 Ok(Some((
1386 key.clone(),
1387 K::from_lua(key, lua.lua())?,
1388 V::from_stack(-1, lua)?,
1389 )))
1390 } else {
1391 Ok(None)
1392 }
1393 })();
1394
1395 match res {
1396 Ok(Some((key, ret_key, value))) => {
1397 self.key = Some(key);
1398 Some(Ok((ret_key, value)))
1399 }
1400 Ok(None) => None,
1401 Err(e) => Some(Err(e)),
1402 }
1403 } else {
1404 None
1405 }
1406 }
1407}
1408
1409pub struct TableSequence<'a, V> {
1415 guard: LuaGuard,
1416 table: &'a Table,
1417 index: Integer,
1418 len: Option<usize>,
1419 _phantom: PhantomData<V>,
1420}
1421
1422impl<V: FromLua> Iterator for TableSequence<'_, V> {
1423 type Item = Result<V>;
1424
1425 fn next(&mut self) -> Option<Self::Item> {
1426 let lua: &RawLua = &self.guard;
1427 let state = lua.state();
1428 unsafe {
1429 let _sg = StackGuard::new(state);
1430 if let Err(err) = check_stack(state, 1) {
1431 return Some(Err(err));
1432 }
1433
1434 lua.push_ref(&self.table.0);
1435 match ffi::lua_rawgeti(state, -1, self.index) {
1436 ffi::LUA_TNIL if self.index as usize > self.len.unwrap_or(0) => None,
1437 _ => {
1438 self.index += 1;
1439 Some(V::from_stack(-1, lua))
1440 }
1441 }
1442 }
1443 }
1444}
1445
1446#[cfg(test)]
1447mod assertions {
1448 use super::*;
1449
1450 #[cfg(not(feature = "send"))]
1451 static_assertions::assert_not_impl_any!(Table: Send);
1452 #[cfg(feature = "send")]
1453 static_assertions::assert_impl_all!(Table: Send, Sync);
1454}