1use std::collections::HashSet;
161use std::fmt;
162use std::marker::PhantomData;
163use std::os::raw::c_void;
164
165use crate::error::{Error, Result};
166use crate::function::Function;
167use crate::state::{LuaGuard, RawLua, WeakLua};
168use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, ObjectLike};
169use crate::types::{Integer, ValueRef};
170use crate::util::{StackGuard, assert_stack, check_stack, get_metatable_ptr};
171use crate::value::{Nil, Value};
172
173#[cfg(feature = "async")]
174use crate::function::AsyncCallFuture;
175
176#[cfg(feature = "serde")]
177use {
178 rustc_hash::FxHashSet,
179 serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer},
180 std::{cell::RefCell, rc::Rc, result::Result as StdResult},
181};
182
183#[derive(Clone, PartialEq)]
185pub struct Table(pub(crate) ValueRef);
186
187impl Table {
188 pub fn set(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
222 if !self.has_metatable() {
224 return self.raw_set(key, value);
225 }
226
227 self.set_protected(key, value)
228 }
229
230 pub(crate) fn set_protected(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
231 let lua = self.0.lua.lock();
232 let state = lua.state();
233 unsafe {
234 let _sg = StackGuard::new(state);
235 check_stack(state, 5)?;
236
237 lua.push_ref(&self.0);
238 key.push_into_stack(&lua)?;
239 value.push_into_stack(&lua)?;
240 protect_lua!(state, 3, 0, fn(state) ffi::lua_settable(state, -3))
241 }
242 }
243
244 pub fn get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
269 if !self.has_metatable() {
271 return self.raw_get(key);
272 }
273
274 self.get_protected(key)
275 }
276
277 pub(crate) fn get_protected<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
278 let lua = self.0.lua.lock();
279 let state = lua.state();
280 unsafe {
281 let _sg = StackGuard::new(state);
282 check_stack(state, 4)?;
283
284 lua.push_ref(&self.0);
285 key.push_into_stack(&lua)?;
286 protect_lua!(state, 2, 1, fn(state) ffi::lua_gettable(state, -2))?;
287
288 V::from_stack(-1, &lua)
289 }
290 }
291
292 pub fn contains_key(&self, key: impl IntoLua) -> Result<bool> {
296 Ok(self.get::<Value>(key)? != Value::Nil)
297 }
298
299 pub fn push(&self, value: impl IntoLua) -> Result<()> {
303 if !self.has_metatable() {
305 return self.raw_push(value);
306 }
307
308 let lua = self.0.lua.lock();
309 let state = lua.state();
310 unsafe {
311 let _sg = StackGuard::new(state);
312 check_stack(state, 4)?;
313
314 lua.push_ref(&self.0);
315 value.push_into_stack(&lua)?;
316 protect_lua!(state, 2, 0, fn(state) {
317 let len = ffi::luaL_len(state, -2) as Integer;
318 ffi::lua_seti(state, -2, len + 1);
319 })?
320 }
321 Ok(())
322 }
323
324 pub fn pop<V: FromLua>(&self) -> Result<V> {
328 if !self.has_metatable() {
330 return self.raw_pop();
331 }
332
333 let lua = self.0.lua.lock();
334 let state = lua.state();
335 unsafe {
336 let _sg = StackGuard::new(state);
337 check_stack(state, 4)?;
338
339 lua.push_ref(&self.0);
340 protect_lua!(state, 1, 1, fn(state) {
341 let len = ffi::luaL_len(state, -1) as Integer;
342 ffi::lua_geti(state, -1, len);
343 ffi::lua_pushnil(state);
344 ffi::lua_seti(state, -3, len);
345 })?;
346 V::from_stack(-1, &lua)
347 }
348 }
349
350 pub fn equals(&self, other: &Self) -> Result<bool> {
380 if self == other {
381 return Ok(true);
382 }
383
384 if let Some(mt) = self.metatable()
388 && let Some(eq_func) = mt.get::<Option<Function>>("__eq")?
389 {
390 return eq_func.call((self, other));
391 }
392 if let Some(mt) = other.metatable()
393 && let Some(eq_func) = mt.get::<Option<Function>>("__eq")?
394 {
395 return eq_func.call((self, other));
396 }
397
398 Ok(false)
399 }
400
401 pub fn raw_set(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
403 let lua = self.0.lua.lock();
404 let state = lua.state();
405 unsafe {
406 #[cfg(feature = "luau")]
407 self.check_readonly_write(&lua)?;
408
409 let _sg = StackGuard::new(state);
410 check_stack(state, 5)?;
411
412 lua.push_ref(&self.0);
413 key.push_into_stack(&lua)?;
414 value.push_into_stack(&lua)?;
415
416 if lua.unlikely_memory_error() {
417 ffi::lua_rawset(state, -3);
418 ffi::lua_pop(state, 1);
419 Ok(())
420 } else {
421 protect_lua!(state, 3, 0, fn(state) ffi::lua_rawset(state, -3))
422 }
423 }
424 }
425
426 pub fn raw_get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
428 let lua = self.0.lua.lock();
429 let state = lua.state();
430 unsafe {
431 let _sg = StackGuard::new(state);
432 check_stack(state, 3)?;
433
434 lua.push_ref(&self.0);
435 key.push_into_stack(&lua)?;
436 ffi::lua_rawget(state, -2);
437
438 V::from_stack(-1, &lua)
439 }
440 }
441
442 pub fn raw_insert(&self, idx: Integer, value: impl IntoLua) -> Result<()> {
447 let size = self.raw_len() as Integer;
448 if idx < 1 || idx > size + 1 {
449 return Err(Error::runtime("index out of bounds"));
450 }
451
452 let lua = self.0.lua.lock();
453 let state = lua.state();
454 unsafe {
455 let _sg = StackGuard::new(state);
456 check_stack(state, 5)?;
457
458 lua.push_ref(&self.0);
459 value.push_into_stack(&lua)?;
460 protect_lua!(state, 2, 0, |state| {
461 for i in (idx..=size).rev() {
462 ffi::lua_rawgeti(state, -2, i);
464 ffi::lua_rawseti(state, -3, i + 1);
465 }
466 ffi::lua_rawseti(state, -2, idx)
467 })
468 }
469 }
470
471 pub fn raw_push(&self, value: impl IntoLua) -> Result<()> {
473 let lua = self.0.lua.lock();
474 let state = lua.state();
475 unsafe {
476 #[cfg(feature = "luau")]
477 self.check_readonly_write(&lua)?;
478
479 let _sg = StackGuard::new(state);
480 check_stack(state, 4)?;
481
482 lua.push_ref(&self.0);
483 value.push_into_stack(&lua)?;
484
485 unsafe fn callback(state: *mut ffi::lua_State) {
486 let len = ffi::lua_rawlen(state, -2) as Integer;
487 ffi::lua_rawseti(state, -2, len + 1);
488 }
489
490 if lua.unlikely_memory_error() {
491 callback(state);
492 } else {
493 protect_lua!(state, 2, 0, fn(state) callback(state))?;
494 }
495 }
496 Ok(())
497 }
498
499 pub fn raw_pop<V: FromLua>(&self) -> Result<V> {
501 let lua = self.0.lua.lock();
502 let state = lua.state();
503 unsafe {
504 #[cfg(feature = "luau")]
505 self.check_readonly_write(&lua)?;
506
507 let _sg = StackGuard::new(state);
508 check_stack(state, 3)?;
509
510 lua.push_ref(&self.0);
511 let len = ffi::lua_rawlen(state, -1) as Integer;
512 ffi::lua_rawgeti(state, -1, len);
513 ffi::lua_pushnil(state);
515 ffi::lua_rawseti(state, -3, len);
516
517 V::from_stack(-1, &lua)
518 }
519 }
520
521 pub fn raw_remove(&self, key: impl IntoLua) -> Result<()> {
529 let lua = self.0.lua.lock();
530 let state = lua.state();
531 let key = key.into_lua(lua.lua())?;
532 match key {
533 Value::Integer(idx) => {
534 let size = self.raw_len() as Integer;
535 if idx < 1 || idx > size {
536 return Err(Error::runtime("index out of bounds"));
537 }
538 unsafe {
539 let _sg = StackGuard::new(state);
540 check_stack(state, 4)?;
541
542 lua.push_ref(&self.0);
543 protect_lua!(state, 1, 0, |state| {
544 for i in idx..size {
545 ffi::lua_rawgeti(state, -1, i + 1);
546 ffi::lua_rawseti(state, -2, i);
547 }
548 ffi::lua_pushnil(state);
549 ffi::lua_rawseti(state, -2, size);
550 })
551 }
552 }
553 _ => self.raw_set(key, Nil),
554 }
555 }
556
557 pub fn clear(&self) -> Result<()> {
562 let lua = self.0.lua.lock();
563 unsafe {
564 #[cfg(feature = "luau")]
565 {
566 self.check_readonly_write(&lua)?;
567 ffi::lua_cleartable(lua.ref_thread(), self.0.index);
568 }
569
570 #[cfg(not(feature = "luau"))]
571 {
572 let state = lua.state();
573 check_stack(state, 4)?;
574
575 lua.push_ref(&self.0);
576
577 ffi::lua_pushnil(state);
579 while ffi::lua_next(state, -2) != 0 {
580 ffi::lua_pop(state, 1); ffi::lua_pushvalue(state, -1); ffi::lua_pushnil(state);
583 ffi::lua_rawset(state, -4);
584 }
585 }
586 }
587
588 Ok(())
589 }
590
591 pub fn len(&self) -> Result<Integer> {
596 if !self.has_metatable() {
598 return Ok(self.raw_len() as Integer);
599 }
600
601 let lua = self.0.lua.lock();
602 let state = lua.state();
603 unsafe {
604 let _sg = StackGuard::new(state);
605 check_stack(state, 4)?;
606
607 lua.push_ref(&self.0);
608 protect_lua!(state, 1, 0, |state| ffi::luaL_len(state, -1))
609 }
610 }
611
612 pub fn raw_len(&self) -> usize {
614 let lua = self.0.lua.lock();
615 unsafe { ffi::lua_rawlen(lua.ref_thread(), self.0.index) }
616 }
617
618 pub fn is_empty(&self) -> bool {
622 let lua = self.0.lua.lock();
623 let ref_thread = lua.ref_thread();
624 unsafe {
625 ffi::lua_pushnil(ref_thread);
626 if ffi::lua_next(ref_thread, self.0.index) == 0 {
627 return true;
628 }
629 ffi::lua_pop(ref_thread, 2);
630 }
631 false
632 }
633
634 pub fn metatable(&self) -> Option<Table> {
640 let lua = self.0.lua.lock();
641 let ref_thread = lua.ref_thread();
642 unsafe {
643 if ffi::lua_getmetatable(ref_thread, self.0.index) == 0 {
644 None
645 } else {
646 Some(Table(lua.pop_ref_thread()))
647 }
648 }
649 }
650
651 pub fn set_metatable(&self, metatable: Option<Table>) -> Result<()> {
656 #[cfg(feature = "luau")]
657 if self.is_readonly() {
658 return Err(Error::runtime("attempt to modify a readonly table"));
659 }
660
661 let lua = self.0.lua.lock();
662 let ref_thread = lua.ref_thread();
663 unsafe {
664 if let Some(metatable) = &metatable {
665 ffi::lua_pushvalue(ref_thread, metatable.0.index);
666 } else {
667 ffi::lua_pushnil(ref_thread);
668 }
669 ffi::lua_setmetatable(ref_thread, self.0.index);
670 }
671 Ok(())
672 }
673
674 #[doc(hidden)]
676 #[inline]
677 pub fn has_metatable(&self) -> bool {
678 let lua = self.0.lua.lock();
679 unsafe { !get_metatable_ptr(lua.ref_thread(), self.0.index).is_null() }
680 }
681
682 #[cfg(any(feature = "luau", doc))]
684 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
685 pub fn set_readonly(&self, enabled: bool) {
686 let lua = self.0.lua.lock();
687 let ref_thread = lua.ref_thread();
688 unsafe {
689 ffi::lua_setreadonly(ref_thread, self.0.index, enabled as _);
690 if !enabled {
691 ffi::lua_setsafeenv(ref_thread, self.0.index, 0);
693 }
694 }
695 }
696
697 #[cfg(any(feature = "luau", doc))]
699 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
700 pub fn is_readonly(&self) -> bool {
701 let lua = self.0.lua.lock();
702 let ref_thread = lua.ref_thread();
703 unsafe { ffi::lua_getreadonly(ref_thread, self.0.index) != 0 }
704 }
705
706 #[cfg(any(feature = "luau", doc))]
716 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
717 pub fn set_safeenv(&self, enabled: bool) {
718 let lua = self.0.lua.lock();
719 unsafe { ffi::lua_setsafeenv(lua.ref_thread(), self.0.index, enabled as _) };
720 }
721
722 #[inline]
729 pub fn to_pointer(&self) -> *const c_void {
730 self.0.to_pointer()
731 }
732
733 pub fn pairs<K: FromLua, V: FromLua>(&self) -> TablePairs<'_, K, V> {
760 TablePairs {
761 guard: self.0.lua.lock(),
762 table: self,
763 key: Some(Nil),
764 _phantom: PhantomData,
765 }
766 }
767
768 pub fn for_each<K, V>(&self, mut f: impl FnMut(K, V) -> Result<()>) -> Result<()>
773 where
774 K: FromLua,
775 V: FromLua,
776 {
777 let lua = self.0.lua.lock();
778 let state = lua.state();
779 unsafe {
780 let _sg = StackGuard::new(state);
781 check_stack(state, 5)?;
782
783 lua.push_ref(&self.0);
784 ffi::lua_pushnil(state);
785 while ffi::lua_next(state, -2) != 0 {
786 let k = K::from_stack(-2, &lua)?;
787 let v = lua.pop::<V>()?;
788 f(k, v)?;
789 }
790 }
791 Ok(())
792 }
793
794 pub fn sequence_values<V: FromLua>(&self) -> TableSequence<'_, V> {
823 TableSequence {
824 guard: self.0.lua.lock(),
825 table: self,
826 index: 1,
827 len: None,
828 _phantom: PhantomData,
829 }
830 }
831
832 #[doc(hidden)]
836 pub fn for_each_value<V: FromLua>(&self, f: impl FnMut(V) -> Result<()>) -> Result<()> {
837 self.for_each_value_by_len(None, f)
838 }
839
840 fn for_each_value_by_len<V: FromLua>(
841 &self,
842 len: impl Into<Option<usize>>,
843 mut f: impl FnMut(V) -> Result<()>,
844 ) -> Result<()> {
845 let len = len.into();
846 let lua = self.0.lua.lock();
847 let state = lua.state();
848 unsafe {
849 let _sg = StackGuard::new(state);
850 check_stack(state, 4)?;
851
852 lua.push_ref(&self.0);
853 for i in 1.. {
854 if len.map(|len| i > len).unwrap_or(false) {
855 break;
856 }
857 let t = ffi::lua_rawgeti(state, -1, i as _);
858 if len.is_none() && t == ffi::LUA_TNIL {
859 break;
860 }
861 f(lua.pop::<V>()?)?;
862 }
863 }
864 Ok(())
865 }
866
867 #[doc(hidden)]
869 pub fn raw_seti(&self, idx: usize, value: impl IntoLua) -> Result<()> {
870 let lua = self.0.lua.lock();
871 let state = lua.state();
872 unsafe {
873 #[cfg(feature = "luau")]
874 self.check_readonly_write(&lua)?;
875
876 let _sg = StackGuard::new(state);
877 check_stack(state, 5)?;
878
879 lua.push_ref(&self.0);
880 value.push_into_stack(&lua)?;
881
882 let idx = idx.try_into().unwrap();
883 if lua.unlikely_memory_error() {
884 ffi::lua_rawseti(state, -2, idx);
885 } else {
886 protect_lua!(state, 2, 0, |state| ffi::lua_rawseti(state, -2, idx))?;
887 }
888 }
889 Ok(())
890 }
891
892 #[cfg(feature = "serde")]
894 fn has_array_metatable(&self) -> bool {
895 let lua = self.0.lua.lock();
896 let state = lua.state();
897 unsafe {
898 let _sg = StackGuard::new(state);
899 assert_stack(state, 3);
900
901 lua.push_ref(&self.0);
902 if ffi::lua_getmetatable(state, -1) == 0 {
903 return false;
904 }
905 crate::serde::push_array_metatable(state);
906 ffi::lua_rawequal(state, -1, -2) != 0
907 }
908 }
909
910 #[cfg(feature = "serde")]
916 fn find_array_len(&self) -> Option<(usize, usize)> {
917 let lua = self.0.lua.lock();
918 let ref_thread = lua.ref_thread();
919 unsafe {
920 let _sg = StackGuard::new(ref_thread);
921
922 let (mut count, mut max_index) = (0, 0);
923 ffi::lua_pushnil(ref_thread);
924 while ffi::lua_next(ref_thread, self.0.index) != 0 {
925 if ffi::lua_type(ref_thread, -2) != ffi::LUA_TNUMBER {
926 return None;
927 }
928
929 let k = ffi::lua_tonumber(ref_thread, -2);
930 if k.trunc() != k || k < 1.0 {
931 return None;
932 }
933 max_index = std::cmp::max(max_index, k as usize);
934 count += 1;
935 ffi::lua_pop(ref_thread, 1);
936 }
937 Some((count, max_index))
938 }
939 }
940
941 #[cfg(feature = "serde")]
954 pub(crate) fn encode_as_array(&self, options: crate::serde::de::Options) -> Option<usize> {
955 if options.detect_mixed_tables {
956 if let Some((len, max_idx)) = self.find_array_len() {
957 if len < 10 || len * 2 >= max_idx {
959 return Some(max_idx);
960 }
961 }
962 } else {
963 let len = self.raw_len();
964 if len > 0 || self.has_array_metatable() {
965 return Some(len);
966 }
967 if options.encode_empty_tables_as_array && self.is_empty() {
968 return Some(0);
969 }
970 }
971 None
972 }
973
974 #[cfg(feature = "luau")]
975 #[inline(always)]
976 fn check_readonly_write(&self, lua: &RawLua) -> Result<()> {
977 if unsafe { ffi::lua_getreadonly(lua.ref_thread(), self.0.index) != 0 } {
978 return Err(Error::runtime("attempt to modify a readonly table"));
979 }
980 Ok(())
981 }
982
983 pub(crate) fn fmt_pretty(
984 &self,
985 fmt: &mut fmt::Formatter,
986 ident: usize,
987 visited: &mut HashSet<*const c_void>,
988 ) -> fmt::Result {
989 visited.insert(self.to_pointer());
990
991 let mut pairs = self.pairs::<Value, Value>().flatten().collect::<Vec<_>>();
993 pairs.sort_by(|(a, _), (b, _)| a.sort_cmp(b));
995 let is_sequence = (pairs.iter().enumerate())
996 .all(|(i, (k, _))| matches!(k, Value::Integer(n) if *n == (i + 1) as Integer));
997 if pairs.is_empty() {
998 return write!(fmt, "{{}}");
999 }
1000 writeln!(fmt, "{{")?;
1001 if is_sequence {
1002 for (_, value) in pairs {
1004 write!(fmt, "{}", " ".repeat(ident + 2))?;
1005 value.fmt_pretty(fmt, true, ident + 2, visited)?;
1006 writeln!(fmt, ",")?;
1007 }
1008 } else {
1009 fn is_simple_key(key: &[u8]) -> bool {
1010 key.iter().take(1).all(|c| c.is_ascii_alphabetic() || *c == b'_')
1011 && key.iter().all(|c| c.is_ascii_alphanumeric() || *c == b'_')
1012 }
1013
1014 for (key, value) in pairs {
1015 match key {
1016 Value::String(key) if is_simple_key(&key.as_bytes()) => {
1017 write!(fmt, "{}{}", " ".repeat(ident + 2), key.display())?;
1018 write!(fmt, " = ")?;
1019 }
1020 _ => {
1021 write!(fmt, "{}[", " ".repeat(ident + 2))?;
1022 key.fmt_pretty(fmt, false, ident + 2, visited)?;
1023 write!(fmt, "] = ")?;
1024 }
1025 }
1026 value.fmt_pretty(fmt, true, ident + 2, visited)?;
1027 writeln!(fmt, ",")?;
1028 }
1029 }
1030 write!(fmt, "{}}}", " ".repeat(ident))
1031 }
1032}
1033
1034impl fmt::Debug for Table {
1035 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1036 if fmt.alternate() {
1037 return self.fmt_pretty(fmt, 0, &mut HashSet::new());
1038 }
1039 fmt.debug_tuple("Table").field(&self.0).finish()
1040 }
1041}
1042
1043impl<T> PartialEq<[T]> for Table
1044where
1045 T: IntoLua + Clone,
1046{
1047 fn eq(&self, other: &[T]) -> bool {
1048 let lua = self.0.lua.lock();
1049 let state = lua.state();
1050 unsafe {
1051 let _sg = StackGuard::new(state);
1052 assert_stack(state, 4);
1053
1054 lua.push_ref(&self.0);
1055
1056 let len = ffi::lua_rawlen(state, -1);
1057 for i in 0..len {
1058 ffi::lua_rawgeti(state, -1, (i + 1) as _);
1059 let val = lua.pop_value();
1060 if val == Nil {
1061 return i == other.len();
1062 }
1063 match other.get(i).map(|v| v.clone().into_lua(lua.lua())) {
1064 Some(Ok(other_val)) if val == other_val => continue,
1065 _ => return false,
1066 }
1067 }
1068 }
1069 true
1070 }
1071}
1072
1073impl<T> PartialEq<&[T]> for Table
1074where
1075 T: IntoLua + Clone,
1076{
1077 #[inline]
1078 fn eq(&self, other: &&[T]) -> bool {
1079 self == *other
1080 }
1081}
1082
1083impl<T, const N: usize> PartialEq<[T; N]> for Table
1084where
1085 T: IntoLua + Clone,
1086{
1087 #[inline]
1088 fn eq(&self, other: &[T; N]) -> bool {
1089 self == &other[..]
1090 }
1091}
1092
1093impl ObjectLike for Table {
1094 #[inline]
1095 fn get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
1096 self.get(key)
1097 }
1098
1099 #[inline]
1100 fn set(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
1101 self.set(key, value)
1102 }
1103
1104 #[inline]
1105 fn call<R>(&self, args: impl IntoLuaMulti) -> Result<R>
1106 where
1107 R: FromLuaMulti,
1108 {
1109 Function(self.0.clone()).call(args)
1111 }
1112
1113 #[cfg(feature = "async")]
1114 #[inline]
1115 fn call_async<R>(&self, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
1116 where
1117 R: FromLuaMulti,
1118 {
1119 Function(self.0.clone()).call_async(args)
1120 }
1121
1122 #[inline]
1123 fn call_method<R>(&self, name: &str, args: impl IntoLuaMulti) -> Result<R>
1124 where
1125 R: FromLuaMulti,
1126 {
1127 self.call_function(name, (self, args))
1128 }
1129
1130 #[cfg(feature = "async")]
1131 fn call_async_method<R>(&self, name: &str, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
1132 where
1133 R: FromLuaMulti,
1134 {
1135 self.call_async_function(name, (self, args))
1136 }
1137
1138 #[inline]
1139 fn call_function<R: FromLuaMulti>(&self, name: &str, args: impl IntoLuaMulti) -> Result<R> {
1140 match self.get(name)? {
1141 Value::Function(func) => func.call(args),
1142 val => {
1143 let msg = format!("attempt to call a {} value (function '{name}')", val.type_name());
1144 Err(Error::runtime(msg))
1145 }
1146 }
1147 }
1148
1149 #[cfg(feature = "async")]
1150 #[inline]
1151 fn call_async_function<R>(&self, name: &str, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
1152 where
1153 R: FromLuaMulti,
1154 {
1155 match self.get(name) {
1156 Ok(Value::Function(func)) => func.call_async(args),
1157 Ok(val) => {
1158 let msg = format!("attempt to call a {} value (function '{name}')", val.type_name());
1159 AsyncCallFuture::error(Error::RuntimeError(msg))
1160 }
1161 Err(err) => AsyncCallFuture::error(err),
1162 }
1163 }
1164
1165 #[inline]
1166 fn to_string(&self) -> Result<String> {
1167 Value::Table(Table(self.0.clone())).to_string()
1168 }
1169
1170 #[inline]
1171 fn to_value(&self) -> Value {
1172 Value::Table(self.clone())
1173 }
1174
1175 #[inline]
1176 fn weak_lua(&self) -> &WeakLua {
1177 &self.0.lua
1178 }
1179}
1180
1181#[cfg(feature = "serde")]
1183pub(crate) struct SerializableTable<'a> {
1184 table: &'a Table,
1185 options: crate::serde::de::Options,
1186 visited: Rc<RefCell<FxHashSet<*const c_void>>>,
1187}
1188
1189#[cfg(feature = "serde")]
1190impl Serialize for Table {
1191 #[inline]
1192 fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
1193 SerializableTable::new(self, Default::default(), Default::default()).serialize(serializer)
1194 }
1195}
1196
1197#[cfg(feature = "serde")]
1198impl<'a> SerializableTable<'a> {
1199 #[inline]
1200 pub(crate) fn new(
1201 table: &'a Table,
1202 options: crate::serde::de::Options,
1203 visited: Rc<RefCell<FxHashSet<*const c_void>>>,
1204 ) -> Self {
1205 Self {
1206 table,
1207 options,
1208 visited,
1209 }
1210 }
1211}
1212
1213impl<V> TableSequence<'_, V> {
1214 #[cfg(feature = "serde")]
1216 pub(crate) fn with_len(mut self, len: usize) -> Self {
1217 self.len = Some(len);
1218 self
1219 }
1220}
1221
1222#[cfg(feature = "serde")]
1223impl Serialize for SerializableTable<'_> {
1224 fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
1225 where
1226 S: Serializer,
1227 {
1228 use crate::serde::de::{MapPairs, RecursionGuard, check_value_for_skip};
1229 use crate::value::SerializableValue;
1230
1231 let convert_result = |res: Result<()>, serialize_err: Option<S::Error>| match res {
1232 Ok(v) => Ok(v),
1233 Err(Error::SerializeError(_)) if serialize_err.is_some() => Err(serialize_err.unwrap()),
1234 Err(Error::SerializeError(msg)) => Err(serde::ser::Error::custom(msg)),
1235 Err(err) => Err(serde::ser::Error::custom(err.to_string())),
1236 };
1237
1238 let options = self.options;
1239 let visited = &self.visited;
1240 let _guard = RecursionGuard::new(self.table, visited);
1241
1242 if let Some(len) = self.table.encode_as_array(self.options) {
1244 let mut seq = serializer.serialize_seq(Some(len))?;
1245 let mut serialize_err = None;
1246 let res = self.table.for_each_value_by_len::<Value>(len, |value| {
1247 let skip = check_value_for_skip(&value, self.options, visited)
1248 .map_err(|err| Error::SerializeError(err.to_string()))?;
1249 if skip {
1250 return Ok(());
1252 }
1253 seq.serialize_element(&SerializableValue::new(&value, options, Some(visited)))
1254 .map_err(|err| {
1255 serialize_err = Some(err);
1256 Error::SerializeError(String::new())
1257 })
1258 });
1259 convert_result(res, serialize_err)?;
1260 return seq.end();
1261 }
1262
1263 let mut map = serializer.serialize_map(None)?;
1265 let mut serialize_err = None;
1266 let mut process_pair = |key, value| {
1267 let skip_key = check_value_for_skip(&key, self.options, visited)
1268 .map_err(|err| Error::SerializeError(err.to_string()))?;
1269 let skip_value = check_value_for_skip(&value, self.options, visited)
1270 .map_err(|err| Error::SerializeError(err.to_string()))?;
1271 if skip_key || skip_value {
1272 return Ok(());
1274 }
1275 map.serialize_entry(
1276 &SerializableValue::new(&key, options, Some(visited)),
1277 &SerializableValue::new(&value, options, Some(visited)),
1278 )
1279 .map_err(|err| {
1280 serialize_err = Some(err);
1281 Error::SerializeError(String::new())
1282 })
1283 };
1284
1285 let res = if !self.options.sort_keys {
1286 self.table.for_each(process_pair)
1288 } else {
1289 MapPairs::new(self.table, self.options.sort_keys)
1290 .map_err(serde::ser::Error::custom)?
1291 .try_for_each(|kv| {
1292 let (key, value) = kv?;
1293 process_pair(key, value)
1294 })
1295 };
1296 convert_result(res, serialize_err)?;
1297 map.end()
1298 }
1299}
1300
1301pub struct TablePairs<'a, K, V> {
1307 guard: LuaGuard,
1308 table: &'a Table,
1309 key: Option<Value>,
1310 _phantom: PhantomData<(K, V)>,
1311}
1312
1313impl<K, V> Iterator for TablePairs<'_, K, V>
1314where
1315 K: FromLua,
1316 V: FromLua,
1317{
1318 type Item = Result<(K, V)>;
1319
1320 fn next(&mut self) -> Option<Self::Item> {
1321 if let Some(prev_key) = self.key.take() {
1322 let lua: &RawLua = &self.guard;
1323 let state = lua.state();
1324
1325 let res = (|| unsafe {
1326 let _sg = StackGuard::new(state);
1327 check_stack(state, 5)?;
1328
1329 lua.push_ref(&self.table.0);
1330 lua.push_value(&prev_key)?;
1331
1332 if ffi::lua_next(state, -2) != 0 {
1336 let key = lua.stack_value(-2, None);
1337 Ok(Some((
1338 key.clone(),
1339 K::from_lua(key, lua.lua())?,
1340 V::from_stack(-1, lua)?,
1341 )))
1342 } else {
1343 Ok(None)
1344 }
1345 })();
1346
1347 match res {
1348 Ok(Some((key, ret_key, value))) => {
1349 self.key = Some(key);
1350 Some(Ok((ret_key, value)))
1351 }
1352 Ok(None) => None,
1353 Err(e) => Some(Err(e)),
1354 }
1355 } else {
1356 None
1357 }
1358 }
1359}
1360
1361pub struct TableSequence<'a, V> {
1367 guard: LuaGuard,
1368 table: &'a Table,
1369 index: Integer,
1370 len: Option<usize>,
1371 _phantom: PhantomData<V>,
1372}
1373
1374impl<V: FromLua> Iterator for TableSequence<'_, V> {
1375 type Item = Result<V>;
1376
1377 fn next(&mut self) -> Option<Self::Item> {
1378 let lua: &RawLua = &self.guard;
1379 let state = lua.state();
1380 unsafe {
1381 let _sg = StackGuard::new(state);
1382 if let Err(err) = check_stack(state, 1) {
1383 return Some(Err(err));
1384 }
1385
1386 lua.push_ref(&self.table.0);
1387 match ffi::lua_rawgeti(state, -1, self.index) {
1388 ffi::LUA_TNIL if self.index as usize > self.len.unwrap_or(0) => None,
1389 _ => {
1390 self.index += 1;
1391 Some(V::from_stack(-1, lua))
1392 }
1393 }
1394 }
1395 }
1396}
1397
1398#[cfg(test)]
1399mod assertions {
1400 use super::*;
1401
1402 #[cfg(not(feature = "send"))]
1403 static_assertions::assert_not_impl_any!(Table: Send);
1404 #[cfg(feature = "send")]
1405 static_assertions::assert_impl_all!(Table: Send, Sync);
1406}