1use std::collections::HashSet;
2use std::fmt;
3use std::marker::PhantomData;
4use std::os::raw::{c_int, c_void};
5use std::string::String as StdString;
6
7use crate::error::{Error, Result};
8use crate::function::Function;
9use crate::state::{LuaGuard, RawLua};
10use crate::traits::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, ObjectLike};
11use crate::types::{Integer, LuaType, ValueRef};
12use crate::util::{assert_stack, check_stack, get_metatable_ptr, StackGuard};
13use crate::value::{Nil, Value};
14
15#[cfg(feature = "async")]
16use crate::function::AsyncCallFuture;
17
18#[cfg(feature = "serde")]
19use {
20 rustc_hash::FxHashSet,
21 serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer},
22 std::{cell::RefCell, rc::Rc, result::Result as StdResult},
23};
24
25#[derive(Clone, PartialEq)]
27pub struct Table(pub(crate) ValueRef);
28
29impl Table {
30 pub fn set(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
64 if !self.has_metatable() {
66 return self.raw_set(key, value);
67 }
68
69 self.set_protected(key, value)
70 }
71
72 pub(crate) fn set_protected(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
73 let lua = self.0.lua.lock();
74 let state = lua.state();
75 unsafe {
76 let _sg = StackGuard::new(state);
77 check_stack(state, 5)?;
78
79 lua.push_ref(&self.0);
80 key.push_into_stack(&lua)?;
81 value.push_into_stack(&lua)?;
82 protect_lua!(state, 3, 0, fn(state) ffi::lua_settable(state, -3))
83 }
84 }
85
86 pub fn get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
111 if !self.has_metatable() {
113 return self.raw_get(key);
114 }
115
116 self.get_protected(key)
117 }
118
119 pub(crate) fn get_protected<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
120 let lua = self.0.lua.lock();
121 let state = lua.state();
122 unsafe {
123 let _sg = StackGuard::new(state);
124 check_stack(state, 4)?;
125
126 lua.push_ref(&self.0);
127 key.push_into_stack(&lua)?;
128 protect_lua!(state, 2, 1, fn(state) ffi::lua_gettable(state, -2))?;
129
130 V::from_stack(-1, &lua)
131 }
132 }
133
134 pub fn contains_key(&self, key: impl IntoLua) -> Result<bool> {
138 Ok(self.get::<Value>(key)? != Value::Nil)
139 }
140
141 pub fn push(&self, value: impl IntoLua) -> Result<()> {
145 if !self.has_metatable() {
147 return self.raw_push(value);
148 }
149
150 let lua = self.0.lua.lock();
151 let state = lua.state();
152 unsafe {
153 let _sg = StackGuard::new(state);
154 check_stack(state, 4)?;
155
156 lua.push_ref(&self.0);
157 value.push_into_stack(&lua)?;
158 protect_lua!(state, 2, 0, fn(state) {
159 let len = ffi::luaL_len(state, -2) as Integer;
160 ffi::lua_seti(state, -2, len + 1);
161 })?
162 }
163 Ok(())
164 }
165
166 pub fn pop<V: FromLua>(&self) -> Result<V> {
170 if !self.has_metatable() {
172 return self.raw_pop();
173 }
174
175 let lua = self.0.lua.lock();
176 let state = lua.state();
177 unsafe {
178 let _sg = StackGuard::new(state);
179 check_stack(state, 4)?;
180
181 lua.push_ref(&self.0);
182 protect_lua!(state, 1, 1, fn(state) {
183 let len = ffi::luaL_len(state, -1) as Integer;
184 ffi::lua_geti(state, -1, len);
185 ffi::lua_pushnil(state);
186 ffi::lua_seti(state, -3, len);
187 })?;
188 V::from_stack(-1, &lua)
189 }
190 }
191
192 pub fn equals(&self, other: &Self) -> Result<bool> {
222 if self == other {
223 return Ok(true);
224 }
225
226 if let Some(mt) = self.metatable() {
230 if mt.contains_key("__eq")? {
231 return mt.get::<Function>("__eq")?.call((self, other));
232 }
233 }
234 if let Some(mt) = other.metatable() {
235 if mt.contains_key("__eq")? {
236 return mt.get::<Function>("__eq")?.call((self, other));
237 }
238 }
239
240 Ok(false)
241 }
242
243 pub fn raw_set(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
245 let lua = self.0.lua.lock();
246 let state = lua.state();
247 unsafe {
248 #[cfg(feature = "luau")]
249 self.check_readonly_write(&lua)?;
250
251 let _sg = StackGuard::new(state);
252 check_stack(state, 5)?;
253
254 lua.push_ref(&self.0);
255 key.push_into_stack(&lua)?;
256 value.push_into_stack(&lua)?;
257
258 if lua.unlikely_memory_error() {
259 ffi::lua_rawset(state, -3);
260 ffi::lua_pop(state, 1);
261 Ok(())
262 } else {
263 protect_lua!(state, 3, 0, fn(state) ffi::lua_rawset(state, -3))
264 }
265 }
266 }
267
268 pub fn raw_get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
270 let lua = self.0.lua.lock();
271 let state = lua.state();
272 unsafe {
273 let _sg = StackGuard::new(state);
274 check_stack(state, 3)?;
275
276 lua.push_ref(&self.0);
277 key.push_into_stack(&lua)?;
278 ffi::lua_rawget(state, -2);
279
280 V::from_stack(-1, &lua)
281 }
282 }
283
284 pub fn raw_insert(&self, idx: Integer, value: impl IntoLua) -> Result<()> {
289 let size = self.raw_len() as Integer;
290 if idx < 1 || idx > size + 1 {
291 return Err(Error::runtime("index out of bounds"));
292 }
293
294 let lua = self.0.lua.lock();
295 let state = lua.state();
296 unsafe {
297 let _sg = StackGuard::new(state);
298 check_stack(state, 5)?;
299
300 lua.push_ref(&self.0);
301 value.push_into_stack(&lua)?;
302 protect_lua!(state, 2, 0, |state| {
303 for i in (idx..=size).rev() {
304 ffi::lua_rawgeti(state, -2, i);
306 ffi::lua_rawseti(state, -3, i + 1);
307 }
308 ffi::lua_rawseti(state, -2, idx)
309 })
310 }
311 }
312
313 pub fn raw_push(&self, value: impl IntoLua) -> Result<()> {
315 let lua = self.0.lua.lock();
316 let state = lua.state();
317 unsafe {
318 #[cfg(feature = "luau")]
319 self.check_readonly_write(&lua)?;
320
321 let _sg = StackGuard::new(state);
322 check_stack(state, 4)?;
323
324 lua.push_ref(&self.0);
325 value.push_into_stack(&lua)?;
326
327 unsafe fn callback(state: *mut ffi::lua_State) {
328 let len = ffi::lua_rawlen(state, -2) as Integer;
329 ffi::lua_rawseti(state, -2, len + 1);
330 }
331
332 if lua.unlikely_memory_error() {
333 callback(state);
334 } else {
335 protect_lua!(state, 2, 0, fn(state) callback(state))?;
336 }
337 }
338 Ok(())
339 }
340
341 pub fn raw_pop<V: FromLua>(&self) -> Result<V> {
343 let lua = self.0.lua.lock();
344 let state = lua.state();
345 unsafe {
346 #[cfg(feature = "luau")]
347 self.check_readonly_write(&lua)?;
348
349 let _sg = StackGuard::new(state);
350 check_stack(state, 3)?;
351
352 lua.push_ref(&self.0);
353 let len = ffi::lua_rawlen(state, -1) as Integer;
354 ffi::lua_rawgeti(state, -1, len);
355 ffi::lua_pushnil(state);
357 ffi::lua_rawseti(state, -3, len);
358
359 V::from_stack(-1, &lua)
360 }
361 }
362
363 pub fn raw_remove(&self, key: impl IntoLua) -> Result<()> {
371 let lua = self.0.lua.lock();
372 let state = lua.state();
373 let key = key.into_lua(lua.lua())?;
374 match key {
375 Value::Integer(idx) => {
376 let size = self.raw_len() as Integer;
377 if idx < 1 || idx > size {
378 return Err(Error::runtime("index out of bounds"));
379 }
380 unsafe {
381 let _sg = StackGuard::new(state);
382 check_stack(state, 4)?;
383
384 lua.push_ref(&self.0);
385 protect_lua!(state, 1, 0, |state| {
386 for i in idx..size {
387 ffi::lua_rawgeti(state, -1, i + 1);
388 ffi::lua_rawseti(state, -2, i);
389 }
390 ffi::lua_pushnil(state);
391 ffi::lua_rawseti(state, -2, size);
392 })
393 }
394 }
395 _ => self.raw_set(key, Nil),
396 }
397 }
398
399 pub fn clear(&self) -> Result<()> {
404 let lua = self.0.lua.lock();
405 unsafe {
406 #[cfg(feature = "luau")]
407 {
408 self.check_readonly_write(&lua)?;
409 ffi::lua_cleartable(lua.ref_thread(), self.0.index);
410 }
411
412 #[cfg(not(feature = "luau"))]
413 {
414 let state = lua.state();
415 check_stack(state, 4)?;
416
417 lua.push_ref(&self.0);
418
419 for i in 1..=ffi::lua_rawlen(state, -1) {
421 ffi::lua_pushnil(state);
422 ffi::lua_rawseti(state, -2, i as Integer);
423 }
424
425 ffi::lua_pushnil(state);
428 while ffi::lua_next(state, -2) != 0 {
429 ffi::lua_pop(state, 1); ffi::lua_pushvalue(state, -1); ffi::lua_pushnil(state);
432 ffi::lua_rawset(state, -4);
433 }
434 }
435 }
436
437 Ok(())
438 }
439
440 pub fn len(&self) -> Result<Integer> {
445 if !self.has_metatable() {
447 return Ok(self.raw_len() as Integer);
448 }
449
450 let lua = self.0.lua.lock();
451 let state = lua.state();
452 unsafe {
453 let _sg = StackGuard::new(state);
454 check_stack(state, 4)?;
455
456 lua.push_ref(&self.0);
457 protect_lua!(state, 1, 0, |state| ffi::luaL_len(state, -1))
458 }
459 }
460
461 pub fn raw_len(&self) -> usize {
463 let lua = self.0.lua.lock();
464 unsafe { ffi::lua_rawlen(lua.ref_thread(), self.0.index) }
465 }
466
467 pub fn is_empty(&self) -> bool {
471 let lua = self.0.lua.lock();
472 let ref_thread = lua.ref_thread();
473 unsafe {
474 ffi::lua_pushnil(ref_thread);
475 if ffi::lua_next(ref_thread, self.0.index) == 0 {
476 return true;
477 }
478 ffi::lua_pop(ref_thread, 2);
479 }
480 false
481 }
482
483 pub fn metatable(&self) -> Option<Table> {
489 let lua = self.0.lua.lock();
490 let ref_thread = lua.ref_thread();
491 unsafe {
492 if ffi::lua_getmetatable(ref_thread, self.0.index) == 0 {
493 None
494 } else {
495 Some(Table(lua.pop_ref_thread()))
496 }
497 }
498 }
499
500 pub fn set_metatable(&self, metatable: Option<Table>) -> Result<()> {
505 #[cfg(feature = "luau")]
506 if self.is_readonly() {
507 return Err(Error::runtime("attempt to modify a readonly table"));
508 }
509
510 let lua = self.0.lua.lock();
511 let ref_thread = lua.ref_thread();
512 unsafe {
513 if let Some(metatable) = &metatable {
514 ffi::lua_pushvalue(ref_thread, metatable.0.index);
515 } else {
516 ffi::lua_pushnil(ref_thread);
517 }
518 ffi::lua_setmetatable(ref_thread, self.0.index);
519 }
520 Ok(())
521 }
522
523 #[doc(hidden)]
525 #[inline]
526 pub fn has_metatable(&self) -> bool {
527 let lua = self.0.lua.lock();
528 unsafe { !get_metatable_ptr(lua.ref_thread(), self.0.index).is_null() }
529 }
530
531 #[cfg(any(feature = "luau", doc))]
533 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
534 pub fn set_readonly(&self, enabled: bool) {
535 let lua = self.0.lua.lock();
536 let ref_thread = lua.ref_thread();
537 unsafe {
538 ffi::lua_setreadonly(ref_thread, self.0.index, enabled as _);
539 if !enabled {
540 ffi::lua_setsafeenv(ref_thread, self.0.index, 0);
542 }
543 }
544 }
545
546 #[cfg(any(feature = "luau", doc))]
548 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
549 pub fn is_readonly(&self) -> bool {
550 let lua = self.0.lua.lock();
551 let ref_thread = lua.ref_thread();
552 unsafe { ffi::lua_getreadonly(ref_thread, self.0.index) != 0 }
553 }
554
555 #[cfg(any(feature = "luau", doc))]
565 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
566 pub fn set_safeenv(&self, enabled: bool) {
567 let lua = self.0.lua.lock();
568 unsafe { ffi::lua_setsafeenv(lua.ref_thread(), self.0.index, enabled as _) };
569 }
570
571 #[inline]
578 pub fn to_pointer(&self) -> *const c_void {
579 self.0.to_pointer()
580 }
581
582 pub fn pairs<K: FromLua, V: FromLua>(&self) -> TablePairs<'_, K, V> {
609 TablePairs {
610 guard: self.0.lua.lock(),
611 table: self,
612 key: Some(Nil),
613 _phantom: PhantomData,
614 }
615 }
616
617 pub fn for_each<K, V>(&self, mut f: impl FnMut(K, V) -> Result<()>) -> Result<()>
622 where
623 K: FromLua,
624 V: FromLua,
625 {
626 let lua = self.0.lua.lock();
627 let state = lua.state();
628 unsafe {
629 let _sg = StackGuard::new(state);
630 check_stack(state, 5)?;
631
632 lua.push_ref(&self.0);
633 ffi::lua_pushnil(state);
634 while ffi::lua_next(state, -2) != 0 {
635 let k = K::from_stack(-2, &lua)?;
636 let v = V::from_stack(-1, &lua)?;
637 f(k, v)?;
638 ffi::lua_pop(state, 1);
640 }
641 }
642 Ok(())
643 }
644
645 pub fn sequence_values<V: FromLua>(&self) -> TableSequence<'_, V> {
674 TableSequence {
675 guard: self.0.lua.lock(),
676 table: self,
677 index: 1,
678 _phantom: PhantomData,
679 }
680 }
681
682 #[doc(hidden)]
684 pub fn for_each_value<V>(&self, mut f: impl FnMut(V) -> Result<()>) -> Result<()>
685 where
686 V: FromLua,
687 {
688 let lua = self.0.lua.lock();
689 let state = lua.state();
690 unsafe {
691 let _sg = StackGuard::new(state);
692 check_stack(state, 4)?;
693
694 lua.push_ref(&self.0);
695 let len = ffi::lua_rawlen(state, -1);
696 for i in 1..=len {
697 ffi::lua_rawgeti(state, -1, i as _);
698 f(V::from_stack(-1, &lua)?)?;
699 ffi::lua_pop(state, 1);
700 }
701 }
702 Ok(())
703 }
704
705 #[doc(hidden)]
707 pub fn raw_seti(&self, idx: usize, value: impl IntoLua) -> Result<()> {
708 let lua = self.0.lua.lock();
709 let state = lua.state();
710 unsafe {
711 #[cfg(feature = "luau")]
712 self.check_readonly_write(&lua)?;
713
714 let _sg = StackGuard::new(state);
715 check_stack(state, 5)?;
716
717 lua.push_ref(&self.0);
718 value.push_into_stack(&lua)?;
719
720 let idx = idx.try_into().unwrap();
721 if lua.unlikely_memory_error() {
722 ffi::lua_rawseti(state, -2, idx);
723 } else {
724 protect_lua!(state, 2, 0, |state| ffi::lua_rawseti(state, -2, idx))?;
725 }
726 }
727 Ok(())
728 }
729
730 #[cfg(feature = "serde")]
731 pub(crate) fn is_array(&self) -> bool {
732 let lua = self.0.lua.lock();
733 let state = lua.state();
734 unsafe {
735 let _sg = StackGuard::new(state);
736 assert_stack(state, 3);
737
738 lua.push_ref(&self.0);
739 if ffi::lua_getmetatable(state, -1) == 0 {
740 return false;
741 }
742 crate::serde::push_array_metatable(state);
743 ffi::lua_rawequal(state, -1, -2) != 0
744 }
745 }
746
747 #[cfg(feature = "luau")]
748 #[inline(always)]
749 fn check_readonly_write(&self, lua: &RawLua) -> Result<()> {
750 if unsafe { ffi::lua_getreadonly(lua.ref_thread(), self.0.index) != 0 } {
751 return Err(Error::runtime("attempt to modify a readonly table"));
752 }
753 Ok(())
754 }
755
756 pub(crate) fn fmt_pretty(
757 &self,
758 fmt: &mut fmt::Formatter,
759 ident: usize,
760 visited: &mut HashSet<*const c_void>,
761 ) -> fmt::Result {
762 visited.insert(self.to_pointer());
763
764 let mut pairs = self.pairs::<Value, Value>().flatten().collect::<Vec<_>>();
766 pairs.sort_by(|(a, _), (b, _)| a.sort_cmp(b));
768 let is_sequence = (pairs.iter().enumerate())
769 .all(|(i, (k, _))| matches!(k, Value::Integer(n) if *n == (i + 1) as Integer));
770 if pairs.is_empty() {
771 return write!(fmt, "{{}}");
772 }
773 writeln!(fmt, "{{")?;
774 if is_sequence {
775 for (_, value) in pairs {
777 write!(fmt, "{}", " ".repeat(ident + 2))?;
778 value.fmt_pretty(fmt, true, ident + 2, visited)?;
779 writeln!(fmt, ",")?;
780 }
781 } else {
782 fn is_simple_key(key: &[u8]) -> bool {
783 key.iter().take(1).all(|c| c.is_ascii_alphabetic() || *c == b'_')
784 && key.iter().all(|c| c.is_ascii_alphanumeric() || *c == b'_')
785 }
786
787 for (key, value) in pairs {
788 match key {
789 Value::String(key) if is_simple_key(&key.as_bytes()) => {
790 write!(fmt, "{}{}", " ".repeat(ident + 2), key.display())?;
791 write!(fmt, " = ")?;
792 }
793 _ => {
794 write!(fmt, "{}[", " ".repeat(ident + 2))?;
795 key.fmt_pretty(fmt, false, ident + 2, visited)?;
796 write!(fmt, "] = ")?;
797 }
798 }
799 value.fmt_pretty(fmt, true, ident + 2, visited)?;
800 writeln!(fmt, ",")?;
801 }
802 }
803 write!(fmt, "{}}}", " ".repeat(ident))
804 }
805}
806
807impl fmt::Debug for Table {
808 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
809 if fmt.alternate() {
810 return self.fmt_pretty(fmt, 0, &mut HashSet::new());
811 }
812 fmt.debug_tuple("Table").field(&self.0).finish()
813 }
814}
815
816impl<T> PartialEq<[T]> for Table
817where
818 T: IntoLua + Clone,
819{
820 fn eq(&self, other: &[T]) -> bool {
821 let lua = self.0.lua.lock();
822 let state = lua.state();
823 unsafe {
824 let _sg = StackGuard::new(state);
825 assert_stack(state, 4);
826
827 lua.push_ref(&self.0);
828
829 let len = ffi::lua_rawlen(state, -1);
830 for i in 0..len {
831 ffi::lua_rawgeti(state, -1, (i + 1) as _);
832 let val = lua.pop_value();
833 if val == Nil {
834 return i == other.len();
835 }
836 match other.get(i).map(|v| v.clone().into_lua(lua.lua())) {
837 Some(Ok(other_val)) if val == other_val => continue,
838 _ => return false,
839 }
840 }
841 }
842 true
843 }
844}
845
846impl<T> PartialEq<&[T]> for Table
847where
848 T: IntoLua + Clone,
849{
850 #[inline]
851 fn eq(&self, other: &&[T]) -> bool {
852 self == *other
853 }
854}
855
856impl<T, const N: usize> PartialEq<[T; N]> for Table
857where
858 T: IntoLua + Clone,
859{
860 #[inline]
861 fn eq(&self, other: &[T; N]) -> bool {
862 self == &other[..]
863 }
864}
865
866impl LuaType for Table {
867 const TYPE_ID: c_int = ffi::LUA_TTABLE;
868}
869
870impl ObjectLike for Table {
871 #[inline]
872 fn get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
873 self.get(key)
874 }
875
876 #[inline]
877 fn set(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
878 self.set(key, value)
879 }
880
881 #[inline]
882 fn call<R>(&self, args: impl IntoLuaMulti) -> Result<R>
883 where
884 R: FromLuaMulti,
885 {
886 Function(self.0.copy()).call(args)
888 }
889
890 #[cfg(feature = "async")]
891 #[inline]
892 fn call_async<R>(&self, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
893 where
894 R: FromLuaMulti,
895 {
896 Function(self.0.copy()).call_async(args)
897 }
898
899 #[inline]
900 fn call_method<R>(&self, name: &str, args: impl IntoLuaMulti) -> Result<R>
901 where
902 R: FromLuaMulti,
903 {
904 self.call_function(name, (self, args))
905 }
906
907 #[cfg(feature = "async")]
908 fn call_async_method<R>(&self, name: &str, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
909 where
910 R: FromLuaMulti,
911 {
912 self.call_async_function(name, (self, args))
913 }
914
915 #[inline]
916 fn call_function<R: FromLuaMulti>(&self, name: &str, args: impl IntoLuaMulti) -> Result<R> {
917 match self.get(name)? {
918 Value::Function(func) => func.call(args),
919 val => {
920 let msg = format!("attempt to call a {} value (function '{name}')", val.type_name());
921 Err(Error::runtime(msg))
922 }
923 }
924 }
925
926 #[cfg(feature = "async")]
927 #[inline]
928 fn call_async_function<R>(&self, name: &str, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
929 where
930 R: FromLuaMulti,
931 {
932 match self.get(name) {
933 Ok(Value::Function(func)) => func.call_async(args),
934 Ok(val) => {
935 let msg = format!("attempt to call a {} value (function '{name}')", val.type_name());
936 AsyncCallFuture::error(Error::RuntimeError(msg))
937 }
938 Err(err) => AsyncCallFuture::error(err),
939 }
940 }
941
942 #[inline]
943 fn to_string(&self) -> Result<StdString> {
944 Value::Table(Table(self.0.copy())).to_string()
945 }
946}
947
948#[cfg(feature = "serde")]
950pub(crate) struct SerializableTable<'a> {
951 table: &'a Table,
952 options: crate::serde::de::Options,
953 visited: Rc<RefCell<FxHashSet<*const c_void>>>,
954}
955
956#[cfg(feature = "serde")]
957impl Serialize for Table {
958 #[inline]
959 fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
960 SerializableTable::new(self, Default::default(), Default::default()).serialize(serializer)
961 }
962}
963
964#[cfg(feature = "serde")]
965impl<'a> SerializableTable<'a> {
966 #[inline]
967 pub(crate) fn new(
968 table: &'a Table,
969 options: crate::serde::de::Options,
970 visited: Rc<RefCell<FxHashSet<*const c_void>>>,
971 ) -> Self {
972 Self {
973 table,
974 options,
975 visited,
976 }
977 }
978}
979
980#[cfg(feature = "serde")]
981impl Serialize for SerializableTable<'_> {
982 fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
983 where
984 S: Serializer,
985 {
986 use crate::serde::de::{check_value_for_skip, MapPairs, RecursionGuard};
987 use crate::value::SerializableValue;
988
989 let convert_result = |res: Result<()>, serialize_err: Option<S::Error>| match res {
990 Ok(v) => Ok(v),
991 Err(Error::SerializeError(_)) if serialize_err.is_some() => Err(serialize_err.unwrap()),
992 Err(Error::SerializeError(msg)) => Err(serde::ser::Error::custom(msg)),
993 Err(err) => Err(serde::ser::Error::custom(err.to_string())),
994 };
995
996 let options = self.options;
997 let visited = &self.visited;
998 let _guard = RecursionGuard::new(self.table, visited);
999
1000 let len = self.table.raw_len();
1002 if len > 0
1003 || self.table.is_array()
1004 || (self.options.encode_empty_tables_as_array && self.table.is_empty())
1005 {
1006 let mut seq = serializer.serialize_seq(Some(len))?;
1007 let mut serialize_err = None;
1008 let res = self.table.for_each_value::<Value>(|value| {
1009 let skip = check_value_for_skip(&value, self.options, visited)
1010 .map_err(|err| Error::SerializeError(err.to_string()))?;
1011 if skip {
1012 return Ok(());
1014 }
1015 seq.serialize_element(&SerializableValue::new(&value, options, Some(visited)))
1016 .map_err(|err| {
1017 serialize_err = Some(err);
1018 Error::SerializeError(StdString::new())
1019 })
1020 });
1021 convert_result(res, serialize_err)?;
1022 return seq.end();
1023 }
1024
1025 let mut map = serializer.serialize_map(None)?;
1027 let mut serialize_err = None;
1028 let mut process_pair = |key, value| {
1029 let skip_key = check_value_for_skip(&key, self.options, visited)
1030 .map_err(|err| Error::SerializeError(err.to_string()))?;
1031 let skip_value = check_value_for_skip(&value, self.options, visited)
1032 .map_err(|err| Error::SerializeError(err.to_string()))?;
1033 if skip_key || skip_value {
1034 return Ok(());
1036 }
1037 map.serialize_entry(
1038 &SerializableValue::new(&key, options, Some(visited)),
1039 &SerializableValue::new(&value, options, Some(visited)),
1040 )
1041 .map_err(|err| {
1042 serialize_err = Some(err);
1043 Error::SerializeError(StdString::new())
1044 })
1045 };
1046
1047 let res = if !self.options.sort_keys {
1048 self.table.for_each(process_pair)
1050 } else {
1051 MapPairs::new(self.table, self.options.sort_keys)
1052 .map_err(serde::ser::Error::custom)?
1053 .try_for_each(|kv| {
1054 let (key, value) = kv?;
1055 process_pair(key, value)
1056 })
1057 };
1058 convert_result(res, serialize_err)?;
1059 map.end()
1060 }
1061}
1062
1063pub struct TablePairs<'a, K, V> {
1069 guard: LuaGuard,
1070 table: &'a Table,
1071 key: Option<Value>,
1072 _phantom: PhantomData<(K, V)>,
1073}
1074
1075impl<K, V> Iterator for TablePairs<'_, K, V>
1076where
1077 K: FromLua,
1078 V: FromLua,
1079{
1080 type Item = Result<(K, V)>;
1081
1082 fn next(&mut self) -> Option<Self::Item> {
1083 if let Some(prev_key) = self.key.take() {
1084 let lua: &RawLua = &self.guard;
1085 let state = lua.state();
1086
1087 let res = (|| unsafe {
1088 let _sg = StackGuard::new(state);
1089 check_stack(state, 5)?;
1090
1091 lua.push_ref(&self.table.0);
1092 lua.push_value(&prev_key)?;
1093
1094 if ffi::lua_next(state, -2) != 0 {
1098 let key = lua.stack_value(-2, None);
1099 Ok(Some((
1100 key.clone(),
1101 K::from_lua(key, lua.lua())?,
1102 V::from_stack(-1, lua)?,
1103 )))
1104 } else {
1105 Ok(None)
1106 }
1107 })();
1108
1109 match res {
1110 Ok(Some((key, ret_key, value))) => {
1111 self.key = Some(key);
1112 Some(Ok((ret_key, value)))
1113 }
1114 Ok(None) => None,
1115 Err(e) => Some(Err(e)),
1116 }
1117 } else {
1118 None
1119 }
1120 }
1121}
1122
1123pub struct TableSequence<'a, V> {
1129 guard: LuaGuard,
1130 table: &'a Table,
1131 index: Integer,
1132 _phantom: PhantomData<V>,
1133}
1134
1135impl<V> Iterator for TableSequence<'_, V>
1136where
1137 V: FromLua,
1138{
1139 type Item = Result<V>;
1140
1141 fn next(&mut self) -> Option<Self::Item> {
1142 let lua: &RawLua = &self.guard;
1143 let state = lua.state();
1144 unsafe {
1145 let _sg = StackGuard::new(state);
1146 if let Err(err) = check_stack(state, 1) {
1147 return Some(Err(err));
1148 }
1149
1150 lua.push_ref(&self.table.0);
1151 match ffi::lua_rawgeti(state, -1, self.index) {
1152 ffi::LUA_TNIL => None,
1153 _ => {
1154 self.index += 1;
1155 Some(V::from_stack(-1, lua))
1156 }
1157 }
1158 }
1159 }
1160}
1161
1162#[cfg(test)]
1163mod assertions {
1164 use super::*;
1165
1166 #[cfg(not(feature = "send"))]
1167 static_assertions::assert_not_impl_any!(Table: Send);
1168 #[cfg(feature = "send")]
1169 static_assertions::assert_impl_all!(Table: Send, Sync);
1170}