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 equals(&self, other: &Self) -> Result<bool> {
374 if self == other {
375 return Ok(true);
376 }
377
378 if let Some(mt) = self.metatable()
382 && let Some(eq_func) = mt.get::<Option<Function>>("__eq")?
383 {
384 return eq_func.call((self, other));
385 }
386 if let Some(mt) = other.metatable()
387 && let Some(eq_func) = mt.get::<Option<Function>>("__eq")?
388 {
389 return eq_func.call((self, other));
390 }
391
392 Ok(false)
393 }
394
395 pub fn raw_set(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
397 let lua = self.0.lua.lock();
398 let state = lua.state();
399 unsafe {
400 #[cfg(feature = "luau")]
401 self.check_readonly_write(&lua)?;
402
403 let _sg = StackGuard::new(state);
404 check_stack(state, 5)?;
405
406 lua.push_ref(&self.0);
407 key.push_into_stack(&lua)?;
408 value.push_into_stack(&lua)?;
409
410 if lua.unlikely_memory_error() {
411 ffi::lua_rawset(state, -3);
412 ffi::lua_pop(state, 1);
413 Ok(())
414 } else {
415 protect_lua!(state, 3, 0, fn(state) ffi::lua_rawset(state, -3))
416 }
417 }
418 }
419
420 pub fn raw_get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
422 let lua = self.0.lua.lock();
423 let state = lua.state();
424 unsafe {
425 let _sg = StackGuard::new(state);
426 check_stack(state, 3)?;
427
428 lua.push_ref(&self.0);
429 key.push_into_stack(&lua)?;
430 ffi::lua_rawget(state, -2);
431
432 V::from_stack(-1, &lua)
433 }
434 }
435
436 pub fn raw_insert(&self, idx: Integer, value: impl IntoLua) -> Result<()> {
441 let size = self.raw_len() as Integer;
442 if idx < 1 || idx > size + 1 {
443 return Err(Error::runtime("index out of bounds"));
444 }
445
446 let lua = self.0.lua.lock();
447 let state = lua.state();
448 unsafe {
449 let _sg = StackGuard::new(state);
450 check_stack(state, 5)?;
451
452 lua.push_ref(&self.0);
453 value.push_into_stack(&lua)?;
454 protect_lua!(state, 2, 0, |state| {
455 for i in (idx..=size).rev() {
456 ffi::lua_rawgeti(state, -2, i);
458 ffi::lua_rawseti(state, -3, i + 1);
459 }
460 ffi::lua_rawseti(state, -2, idx)
461 })
462 }
463 }
464
465 pub fn raw_push(&self, value: impl IntoLua) -> Result<()> {
467 let lua = self.0.lua.lock();
468 let state = lua.state();
469 unsafe {
470 #[cfg(feature = "luau")]
471 self.check_readonly_write(&lua)?;
472
473 let _sg = StackGuard::new(state);
474 check_stack(state, 4)?;
475
476 lua.push_ref(&self.0);
477 value.push_into_stack(&lua)?;
478
479 unsafe fn callback(state: *mut ffi::lua_State) {
480 let len = ffi::lua_rawlen(state, -2) as Integer;
481 ffi::lua_rawseti(state, -2, len + 1);
482 }
483
484 if lua.unlikely_memory_error() {
485 callback(state);
486 } else {
487 protect_lua!(state, 2, 0, fn(state) callback(state))?;
488 }
489 }
490 Ok(())
491 }
492
493 pub fn raw_pop<V: FromLua>(&self) -> Result<V> {
495 let lua = self.0.lua.lock();
496 let state = lua.state();
497 unsafe {
498 #[cfg(feature = "luau")]
499 self.check_readonly_write(&lua)?;
500
501 let _sg = StackGuard::new(state);
502 check_stack(state, 3)?;
503
504 lua.push_ref(&self.0);
505 let len = ffi::lua_rawlen(state, -1) as Integer;
506 ffi::lua_rawgeti(state, -1, len);
507 ffi::lua_pushnil(state);
509 ffi::lua_rawseti(state, -3, len);
510
511 V::from_stack(-1, &lua)
512 }
513 }
514
515 pub fn raw_remove(&self, key: impl IntoLua) -> Result<()> {
523 let lua = self.0.lua.lock();
524 let state = lua.state();
525 let key = key.into_lua(lua.lua())?;
526 match key {
527 Value::Integer(idx) => {
528 let size = self.raw_len() as Integer;
529 if idx < 1 || idx > size {
530 return Err(Error::runtime("index out of bounds"));
531 }
532 unsafe {
533 let _sg = StackGuard::new(state);
534 check_stack(state, 4)?;
535
536 lua.push_ref(&self.0);
537 protect_lua!(state, 1, 0, |state| {
538 for i in idx..size {
539 ffi::lua_rawgeti(state, -1, i + 1);
540 ffi::lua_rawseti(state, -2, i);
541 }
542 ffi::lua_pushnil(state);
543 ffi::lua_rawseti(state, -2, size);
544 })
545 }
546 }
547 _ => self.raw_set(key, Nil),
548 }
549 }
550
551 pub fn clear(&self) -> Result<()> {
556 let lua = self.0.lua.lock();
557 unsafe {
558 #[cfg(feature = "luau")]
559 {
560 self.check_readonly_write(&lua)?;
561 ffi::lua_cleartable(lua.ref_thread(), self.0.index);
562 }
563
564 #[cfg(not(feature = "luau"))]
565 {
566 let state = lua.state();
567 check_stack(state, 4)?;
568
569 lua.push_ref(&self.0);
570
571 ffi::lua_pushnil(state);
573 while ffi::lua_next(state, -2) != 0 {
574 ffi::lua_pop(state, 1); ffi::lua_pushvalue(state, -1); ffi::lua_pushnil(state);
577 ffi::lua_rawset(state, -4);
578 }
579 }
580 }
581
582 Ok(())
583 }
584
585 pub fn len(&self) -> Result<Integer> {
590 if !self.has_metatable() {
592 return Ok(self.raw_len() as Integer);
593 }
594
595 let lua = self.0.lua.lock();
596 let state = lua.state();
597 unsafe {
598 let _sg = StackGuard::new(state);
599 check_stack(state, 4)?;
600
601 lua.push_ref(&self.0);
602 protect_lua!(state, 1, 0, |state| ffi::luaL_len(state, -1))
603 }
604 }
605
606 pub fn raw_len(&self) -> usize {
608 let lua = self.0.lua.lock();
609 unsafe { ffi::lua_rawlen(lua.ref_thread(), self.0.index) }
610 }
611
612 pub fn is_empty(&self) -> bool {
616 let lua = self.0.lua.lock();
617 let ref_thread = lua.ref_thread();
618 unsafe {
619 ffi::lua_pushnil(ref_thread);
620 if ffi::lua_next(ref_thread, self.0.index) == 0 {
621 return true;
622 }
623 ffi::lua_pop(ref_thread, 2);
624 }
625 false
626 }
627
628 pub fn metatable(&self) -> Option<Table> {
634 let lua = self.0.lua.lock();
635 let ref_thread = lua.ref_thread();
636 unsafe {
637 if ffi::lua_getmetatable(ref_thread, self.0.index) == 0 {
638 None
639 } else {
640 Some(Table(lua.pop_ref_thread()))
641 }
642 }
643 }
644
645 pub fn set_metatable(&self, metatable: Option<Table>) -> Result<()> {
650 #[cfg(feature = "luau")]
651 if self.is_readonly() {
652 return Err(Error::runtime("attempt to modify a readonly table"));
653 }
654
655 let lua = self.0.lua.lock();
656 let ref_thread = lua.ref_thread();
657 unsafe {
658 if let Some(metatable) = &metatable {
659 ffi::lua_pushvalue(ref_thread, metatable.0.index);
660 } else {
661 ffi::lua_pushnil(ref_thread);
662 }
663 ffi::lua_setmetatable(ref_thread, self.0.index);
664 }
665 Ok(())
666 }
667
668 #[doc(hidden)]
670 #[inline]
671 pub fn has_metatable(&self) -> bool {
672 let lua = self.0.lua.lock();
673 unsafe { !get_metatable_ptr(lua.ref_thread(), self.0.index).is_null() }
674 }
675
676 #[cfg(any(feature = "luau", doc))]
678 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
679 pub fn set_readonly(&self, enabled: bool) {
680 let lua = self.0.lua.lock();
681 let ref_thread = lua.ref_thread();
682 unsafe {
683 ffi::lua_setreadonly(ref_thread, self.0.index, enabled as _);
684 if !enabled {
685 ffi::lua_setsafeenv(ref_thread, self.0.index, 0);
687 }
688 }
689 }
690
691 #[cfg(any(feature = "luau", doc))]
693 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
694 pub fn is_readonly(&self) -> bool {
695 let lua = self.0.lua.lock();
696 let ref_thread = lua.ref_thread();
697 unsafe { ffi::lua_getreadonly(ref_thread, self.0.index) != 0 }
698 }
699
700 #[cfg(any(feature = "luau", doc))]
710 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
711 pub fn set_safeenv(&self, enabled: bool) {
712 let lua = self.0.lua.lock();
713 unsafe { ffi::lua_setsafeenv(lua.ref_thread(), self.0.index, enabled as _) };
714 }
715
716 #[inline]
723 pub fn to_pointer(&self) -> *const c_void {
724 self.0.to_pointer()
725 }
726
727 pub fn pairs<K: FromLua, V: FromLua>(&self) -> TablePairs<'_, K, V> {
754 TablePairs {
755 guard: self.0.lua.lock(),
756 table: self,
757 key: Some(Nil),
758 _phantom: PhantomData,
759 }
760 }
761
762 pub fn for_each<K, V>(&self, mut f: impl FnMut(K, V) -> Result<()>) -> Result<()>
767 where
768 K: FromLua,
769 V: FromLua,
770 {
771 let lua = self.0.lua.lock();
772 let state = lua.state();
773 unsafe {
774 let _sg = StackGuard::new(state);
775 check_stack(state, 5)?;
776
777 lua.push_ref(&self.0);
778 ffi::lua_pushnil(state);
779 while ffi::lua_next(state, -2) != 0 {
780 let k = K::from_stack(-2, &lua)?;
781 let v = lua.pop::<V>()?;
782 f(k, v)?;
783 }
784 }
785 Ok(())
786 }
787
788 pub fn sequence_values<V: FromLua>(&self) -> TableSequence<'_, V> {
817 TableSequence {
818 guard: self.0.lua.lock(),
819 table: self,
820 index: 1,
821 len: None,
822 _phantom: PhantomData,
823 }
824 }
825
826 #[doc(hidden)]
830 pub fn for_each_value<V: FromLua>(&self, f: impl FnMut(V) -> Result<()>) -> Result<()> {
831 self.for_each_value_by_len(None, f)
832 }
833
834 fn for_each_value_by_len<V: FromLua>(
835 &self,
836 len: impl Into<Option<usize>>,
837 mut f: impl FnMut(V) -> Result<()>,
838 ) -> Result<()> {
839 let len = len.into();
840 let lua = self.0.lua.lock();
841 let state = lua.state();
842 unsafe {
843 let _sg = StackGuard::new(state);
844 check_stack(state, 4)?;
845
846 lua.push_ref(&self.0);
847 for i in 1.. {
848 if len.map(|len| i > len).unwrap_or(false) {
849 break;
850 }
851 let t = ffi::lua_rawgeti(state, -1, i as _);
852 if len.is_none() && t == ffi::LUA_TNIL {
853 break;
854 }
855 f(lua.pop::<V>()?)?;
856 }
857 }
858 Ok(())
859 }
860
861 #[doc(hidden)]
863 pub fn raw_seti(&self, idx: usize, value: impl IntoLua) -> Result<()> {
864 let lua = self.0.lua.lock();
865 let state = lua.state();
866 unsafe {
867 #[cfg(feature = "luau")]
868 self.check_readonly_write(&lua)?;
869
870 let _sg = StackGuard::new(state);
871 check_stack(state, 5)?;
872
873 lua.push_ref(&self.0);
874 value.push_into_stack(&lua)?;
875
876 let idx = idx.try_into().unwrap();
877 if lua.unlikely_memory_error() {
878 ffi::lua_rawseti(state, -2, idx);
879 } else {
880 protect_lua!(state, 2, 0, |state| ffi::lua_rawseti(state, -2, idx))?;
881 }
882 }
883 Ok(())
884 }
885
886 #[cfg(feature = "serde")]
888 fn has_array_metatable(&self) -> bool {
889 let lua = self.0.lua.lock();
890 let state = lua.state();
891 unsafe {
892 let _sg = StackGuard::new(state);
893 assert_stack(state, 3);
894
895 lua.push_ref(&self.0);
896 if ffi::lua_getmetatable(state, -1) == 0 {
897 return false;
898 }
899 crate::serde::push_array_metatable(state);
900 ffi::lua_rawequal(state, -1, -2) != 0
901 }
902 }
903
904 #[cfg(feature = "serde")]
910 fn find_array_len(&self) -> Option<(usize, usize)> {
911 let lua = self.0.lua.lock();
912 let ref_thread = lua.ref_thread();
913 unsafe {
914 let _sg = StackGuard::new(ref_thread);
915
916 let (mut count, mut max_index) = (0, 0);
917 ffi::lua_pushnil(ref_thread);
918 while ffi::lua_next(ref_thread, self.0.index) != 0 {
919 if ffi::lua_type(ref_thread, -2) != ffi::LUA_TNUMBER {
920 return None;
921 }
922
923 let k = ffi::lua_tonumber(ref_thread, -2);
924 if k.trunc() != k || k < 1.0 {
925 return None;
926 }
927 max_index = std::cmp::max(max_index, k as usize);
928 count += 1;
929 ffi::lua_pop(ref_thread, 1);
930 }
931 Some((count, max_index))
932 }
933 }
934
935 #[cfg(feature = "serde")]
948 pub(crate) fn encode_as_array(&self, options: crate::serde::de::Options) -> Option<usize> {
949 if options.detect_mixed_tables {
950 if let Some((len, max_idx)) = self.find_array_len() {
951 if len < 10 || len * 2 >= max_idx {
953 return Some(max_idx);
954 }
955 }
956 } else {
957 let len = self.raw_len();
958 if len > 0 || self.has_array_metatable() {
959 return Some(len);
960 }
961 if options.encode_empty_tables_as_array && self.is_empty() {
962 return Some(0);
963 }
964 }
965 None
966 }
967
968 #[cfg(feature = "luau")]
969 #[inline(always)]
970 fn check_readonly_write(&self, lua: &RawLua) -> Result<()> {
971 if unsafe { ffi::lua_getreadonly(lua.ref_thread(), self.0.index) != 0 } {
972 return Err(Error::runtime("attempt to modify a readonly table"));
973 }
974 Ok(())
975 }
976
977 pub(crate) fn fmt_pretty(
978 &self,
979 fmt: &mut fmt::Formatter,
980 ident: usize,
981 visited: &mut HashSet<*const c_void>,
982 ) -> fmt::Result {
983 visited.insert(self.to_pointer());
984
985 let mut pairs = self.pairs::<Value, Value>().flatten().collect::<Vec<_>>();
987 pairs.sort_by(|(a, _), (b, _)| a.sort_cmp(b));
989 let is_sequence = (pairs.iter().enumerate())
990 .all(|(i, (k, _))| matches!(k, Value::Integer(n) if *n == (i + 1) as Integer));
991 if pairs.is_empty() {
992 return write!(fmt, "{{}}");
993 }
994 writeln!(fmt, "{{")?;
995 if is_sequence {
996 for (_, value) in pairs {
998 write!(fmt, "{}", " ".repeat(ident + 2))?;
999 value.fmt_pretty(fmt, true, ident + 2, visited)?;
1000 writeln!(fmt, ",")?;
1001 }
1002 } else {
1003 fn is_simple_key(key: &[u8]) -> bool {
1004 key.iter().take(1).all(|c| c.is_ascii_alphabetic() || *c == b'_')
1005 && key.iter().all(|c| c.is_ascii_alphanumeric() || *c == b'_')
1006 }
1007
1008 for (key, value) in pairs {
1009 match key {
1010 Value::String(key) if is_simple_key(&key.as_bytes()) => {
1011 write!(fmt, "{}{}", " ".repeat(ident + 2), key.display())?;
1012 write!(fmt, " = ")?;
1013 }
1014 _ => {
1015 write!(fmt, "{}[", " ".repeat(ident + 2))?;
1016 key.fmt_pretty(fmt, false, ident + 2, visited)?;
1017 write!(fmt, "] = ")?;
1018 }
1019 }
1020 value.fmt_pretty(fmt, true, ident + 2, visited)?;
1021 writeln!(fmt, ",")?;
1022 }
1023 }
1024 write!(fmt, "{}}}", " ".repeat(ident))
1025 }
1026}
1027
1028impl fmt::Debug for Table {
1029 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1030 if fmt.alternate() {
1031 return self.fmt_pretty(fmt, 0, &mut HashSet::new());
1032 }
1033 fmt.debug_tuple("Table").field(&self.0).finish()
1034 }
1035}
1036
1037impl<T> PartialEq<[T]> for Table
1038where
1039 T: IntoLua + Clone,
1040{
1041 fn eq(&self, other: &[T]) -> bool {
1042 let lua = self.0.lua.lock();
1043 let state = lua.state();
1044 unsafe {
1045 let _sg = StackGuard::new(state);
1046 assert_stack(state, 4);
1047
1048 lua.push_ref(&self.0);
1049
1050 let len = ffi::lua_rawlen(state, -1);
1051 for i in 0..len {
1052 ffi::lua_rawgeti(state, -1, (i + 1) as _);
1053 let val = lua.pop_value();
1054 if val == Nil {
1055 return i == other.len();
1056 }
1057 match other.get(i).map(|v| v.clone().into_lua(lua.lua())) {
1058 Some(Ok(other_val)) if val == other_val => continue,
1059 _ => return false,
1060 }
1061 }
1062 }
1063 true
1064 }
1065}
1066
1067impl<T> PartialEq<&[T]> for Table
1068where
1069 T: IntoLua + Clone,
1070{
1071 #[inline]
1072 fn eq(&self, other: &&[T]) -> bool {
1073 self == *other
1074 }
1075}
1076
1077impl<T, const N: usize> PartialEq<[T; N]> for Table
1078where
1079 T: IntoLua + Clone,
1080{
1081 #[inline]
1082 fn eq(&self, other: &[T; N]) -> bool {
1083 self == &other[..]
1084 }
1085}
1086
1087impl ObjectLike for Table {
1088 #[inline]
1089 fn get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
1090 self.get(key)
1091 }
1092
1093 #[inline]
1094 fn set(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
1095 self.set(key, value)
1096 }
1097
1098 #[inline]
1099 fn call<R>(&self, args: impl IntoLuaMulti) -> Result<R>
1100 where
1101 R: FromLuaMulti,
1102 {
1103 Function(self.0.clone()).call(args)
1105 }
1106
1107 #[cfg(feature = "async")]
1108 #[inline]
1109 fn call_async<R>(&self, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
1110 where
1111 R: FromLuaMulti,
1112 {
1113 Function(self.0.clone()).call_async(args)
1114 }
1115
1116 #[inline]
1117 fn call_method<R>(&self, name: &str, args: impl IntoLuaMulti) -> Result<R>
1118 where
1119 R: FromLuaMulti,
1120 {
1121 self.call_function(name, (self, args))
1122 }
1123
1124 #[cfg(feature = "async")]
1125 fn call_async_method<R>(&self, name: &str, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
1126 where
1127 R: FromLuaMulti,
1128 {
1129 self.call_async_function(name, (self, args))
1130 }
1131
1132 #[inline]
1133 fn call_function<R: FromLuaMulti>(&self, name: &str, args: impl IntoLuaMulti) -> Result<R> {
1134 match self.get(name)? {
1135 Value::Function(func) => func.call(args),
1136 val => {
1137 let msg = format!("attempt to call a {} value (function '{name}')", val.type_name());
1138 Err(Error::runtime(msg))
1139 }
1140 }
1141 }
1142
1143 #[cfg(feature = "async")]
1144 #[inline]
1145 fn call_async_function<R>(&self, name: &str, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
1146 where
1147 R: FromLuaMulti,
1148 {
1149 match self.get(name) {
1150 Ok(Value::Function(func)) => func.call_async(args),
1151 Ok(val) => {
1152 let msg = format!("attempt to call a {} value (function '{name}')", val.type_name());
1153 AsyncCallFuture::error(Error::RuntimeError(msg))
1154 }
1155 Err(err) => AsyncCallFuture::error(err),
1156 }
1157 }
1158
1159 #[inline]
1160 fn to_string(&self) -> Result<String> {
1161 Value::Table(Table(self.0.clone())).to_string()
1162 }
1163
1164 #[inline]
1165 fn to_value(&self) -> Value {
1166 Value::Table(self.clone())
1167 }
1168
1169 #[inline]
1170 fn weak_lua(&self) -> &WeakLua {
1171 &self.0.lua
1172 }
1173}
1174
1175#[cfg(feature = "serde")]
1177pub(crate) struct SerializableTable<'a> {
1178 table: &'a Table,
1179 options: crate::serde::de::Options,
1180 visited: Rc<RefCell<FxHashSet<*const c_void>>>,
1181}
1182
1183#[cfg(feature = "serde")]
1184impl Serialize for Table {
1185 #[inline]
1186 fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
1187 SerializableTable::new(self, Default::default(), Default::default()).serialize(serializer)
1188 }
1189}
1190
1191#[cfg(feature = "serde")]
1192impl<'a> SerializableTable<'a> {
1193 #[inline]
1194 pub(crate) fn new(
1195 table: &'a Table,
1196 options: crate::serde::de::Options,
1197 visited: Rc<RefCell<FxHashSet<*const c_void>>>,
1198 ) -> Self {
1199 Self {
1200 table,
1201 options,
1202 visited,
1203 }
1204 }
1205}
1206
1207impl<V> TableSequence<'_, V> {
1208 #[cfg(feature = "serde")]
1210 pub(crate) fn with_len(mut self, len: usize) -> Self {
1211 self.len = Some(len);
1212 self
1213 }
1214}
1215
1216#[cfg(feature = "serde")]
1217impl Serialize for SerializableTable<'_> {
1218 fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
1219 where
1220 S: Serializer,
1221 {
1222 use crate::serde::de::{MapPairs, RecursionGuard, check_value_for_skip};
1223 use crate::value::SerializableValue;
1224
1225 let convert_result = |res: Result<()>, serialize_err: Option<S::Error>| match res {
1226 Ok(v) => Ok(v),
1227 Err(Error::SerializeError(_)) if serialize_err.is_some() => Err(serialize_err.unwrap()),
1228 Err(Error::SerializeError(msg)) => Err(serde::ser::Error::custom(msg)),
1229 Err(err) => Err(serde::ser::Error::custom(err.to_string())),
1230 };
1231
1232 let options = self.options;
1233 let visited = &self.visited;
1234 let _guard = RecursionGuard::new(self.table, visited);
1235
1236 if let Some(len) = self.table.encode_as_array(self.options) {
1238 let mut seq = serializer.serialize_seq(Some(len))?;
1239 let mut serialize_err = None;
1240 let res = self.table.for_each_value_by_len::<Value>(len, |value| {
1241 let skip = check_value_for_skip(&value, self.options, visited)
1242 .map_err(|err| Error::SerializeError(err.to_string()))?;
1243 if skip {
1244 return Ok(());
1246 }
1247 seq.serialize_element(&SerializableValue::new(&value, options, Some(visited)))
1248 .map_err(|err| {
1249 serialize_err = Some(err);
1250 Error::SerializeError(String::new())
1251 })
1252 });
1253 convert_result(res, serialize_err)?;
1254 return seq.end();
1255 }
1256
1257 let mut map = serializer.serialize_map(None)?;
1259 let mut serialize_err = None;
1260 let mut process_pair = |key, value| {
1261 let skip_key = check_value_for_skip(&key, self.options, visited)
1262 .map_err(|err| Error::SerializeError(err.to_string()))?;
1263 let skip_value = check_value_for_skip(&value, self.options, visited)
1264 .map_err(|err| Error::SerializeError(err.to_string()))?;
1265 if skip_key || skip_value {
1266 return Ok(());
1268 }
1269 map.serialize_entry(
1270 &SerializableValue::new(&key, options, Some(visited)),
1271 &SerializableValue::new(&value, options, Some(visited)),
1272 )
1273 .map_err(|err| {
1274 serialize_err = Some(err);
1275 Error::SerializeError(String::new())
1276 })
1277 };
1278
1279 let res = if !self.options.sort_keys {
1280 self.table.for_each(process_pair)
1282 } else {
1283 MapPairs::new(self.table, self.options.sort_keys)
1284 .map_err(serde::ser::Error::custom)?
1285 .try_for_each(|kv| {
1286 let (key, value) = kv?;
1287 process_pair(key, value)
1288 })
1289 };
1290 convert_result(res, serialize_err)?;
1291 map.end()
1292 }
1293}
1294
1295pub struct TablePairs<'a, K, V> {
1301 guard: LuaGuard,
1302 table: &'a Table,
1303 key: Option<Value>,
1304 _phantom: PhantomData<(K, V)>,
1305}
1306
1307impl<K, V> Iterator for TablePairs<'_, K, V>
1308where
1309 K: FromLua,
1310 V: FromLua,
1311{
1312 type Item = Result<(K, V)>;
1313
1314 fn next(&mut self) -> Option<Self::Item> {
1315 if let Some(prev_key) = self.key.take() {
1316 let lua: &RawLua = &self.guard;
1317 let state = lua.state();
1318
1319 let res = (|| unsafe {
1320 let _sg = StackGuard::new(state);
1321 check_stack(state, 5)?;
1322
1323 lua.push_ref(&self.table.0);
1324 lua.push_value(&prev_key)?;
1325
1326 if ffi::lua_next(state, -2) != 0 {
1330 let key = lua.stack_value(-2, None);
1331 Ok(Some((
1332 key.clone(),
1333 K::from_lua(key, lua.lua())?,
1334 V::from_stack(-1, lua)?,
1335 )))
1336 } else {
1337 Ok(None)
1338 }
1339 })();
1340
1341 match res {
1342 Ok(Some((key, ret_key, value))) => {
1343 self.key = Some(key);
1344 Some(Ok((ret_key, value)))
1345 }
1346 Ok(None) => None,
1347 Err(e) => Some(Err(e)),
1348 }
1349 } else {
1350 None
1351 }
1352 }
1353}
1354
1355pub struct TableSequence<'a, V> {
1361 guard: LuaGuard,
1362 table: &'a Table,
1363 index: Integer,
1364 len: Option<usize>,
1365 _phantom: PhantomData<V>,
1366}
1367
1368impl<V: FromLua> Iterator for TableSequence<'_, V> {
1369 type Item = Result<V>;
1370
1371 fn next(&mut self) -> Option<Self::Item> {
1372 let lua: &RawLua = &self.guard;
1373 let state = lua.state();
1374 unsafe {
1375 let _sg = StackGuard::new(state);
1376 if let Err(err) = check_stack(state, 1) {
1377 return Some(Err(err));
1378 }
1379
1380 lua.push_ref(&self.table.0);
1381 match ffi::lua_rawgeti(state, -1, self.index) {
1382 ffi::LUA_TNIL if self.index as usize > self.len.unwrap_or(0) => None,
1383 _ => {
1384 self.index += 1;
1385 Some(V::from_stack(-1, lua))
1386 }
1387 }
1388 }
1389 }
1390}
1391
1392#[cfg(test)]
1393mod assertions {
1394 use super::*;
1395
1396 #[cfg(not(feature = "send"))]
1397 static_assertions::assert_not_impl_any!(Table: Send);
1398 #[cfg(feature = "send")]
1399 static_assertions::assert_impl_all!(Table: Send, Sync);
1400}