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 futures_util::future::{self, Either, Future};
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 state = lua.state();
491 unsafe {
492 let _sg = StackGuard::new(state);
493 assert_stack(state, 2);
494
495 lua.push_ref(&self.0);
496 if ffi::lua_getmetatable(state, -1) == 0 {
497 None
498 } else {
499 Some(Table(lua.pop_ref()))
500 }
501 }
502 }
503
504 pub fn set_metatable(&self, metatable: Option<Table>) {
509 #[cfg(feature = "luau")]
511 if self.is_readonly() {
512 panic!("attempt to modify a readonly table");
513 }
514
515 let lua = self.0.lua.lock();
516 let state = lua.state();
517 unsafe {
518 let _sg = StackGuard::new(state);
519 assert_stack(state, 2);
520
521 lua.push_ref(&self.0);
522 if let Some(metatable) = metatable {
523 lua.push_ref(&metatable.0);
524 } else {
525 ffi::lua_pushnil(state);
526 }
527 ffi::lua_setmetatable(state, -2);
528 }
529 }
530
531 #[doc(hidden)]
533 #[inline]
534 pub fn has_metatable(&self) -> bool {
535 let lua = self.0.lua.lock();
536 unsafe { !get_metatable_ptr(lua.ref_thread(), self.0.index).is_null() }
537 }
538
539 #[cfg(any(feature = "luau", doc))]
541 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
542 pub fn set_readonly(&self, enabled: bool) {
543 let lua = self.0.lua.lock();
544 let ref_thread = lua.ref_thread();
545 unsafe {
546 ffi::lua_setreadonly(ref_thread, self.0.index, enabled as _);
547 if !enabled {
548 ffi::lua_setsafeenv(ref_thread, self.0.index, 0);
550 }
551 }
552 }
553
554 #[cfg(any(feature = "luau", doc))]
556 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
557 pub fn is_readonly(&self) -> bool {
558 let lua = self.0.lua.lock();
559 let ref_thread = lua.ref_thread();
560 unsafe { ffi::lua_getreadonly(ref_thread, self.0.index) != 0 }
561 }
562
563 #[cfg(any(feature = "luau", doc))]
573 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
574 pub fn set_safeenv(&self, enabled: bool) {
575 let lua = self.0.lua.lock();
576 unsafe { ffi::lua_setsafeenv(lua.ref_thread(), self.0.index, enabled as _) };
577 }
578
579 #[inline]
586 pub fn to_pointer(&self) -> *const c_void {
587 self.0.to_pointer()
588 }
589
590 pub fn pairs<K: FromLua, V: FromLua>(&self) -> TablePairs<K, V> {
617 TablePairs {
618 guard: self.0.lua.lock(),
619 table: self,
620 key: Some(Nil),
621 _phantom: PhantomData,
622 }
623 }
624
625 pub fn for_each<K, V>(&self, mut f: impl FnMut(K, V) -> Result<()>) -> Result<()>
630 where
631 K: FromLua,
632 V: FromLua,
633 {
634 let lua = self.0.lua.lock();
635 let state = lua.state();
636 unsafe {
637 let _sg = StackGuard::new(state);
638 check_stack(state, 5)?;
639
640 lua.push_ref(&self.0);
641 ffi::lua_pushnil(state);
642 while ffi::lua_next(state, -2) != 0 {
643 let k = K::from_stack(-2, &lua)?;
644 let v = V::from_stack(-1, &lua)?;
645 f(k, v)?;
646 ffi::lua_pop(state, 1);
648 }
649 }
650 Ok(())
651 }
652
653 pub fn sequence_values<V: FromLua>(&self) -> TableSequence<V> {
682 TableSequence {
683 guard: self.0.lua.lock(),
684 table: self,
685 index: 1,
686 _phantom: PhantomData,
687 }
688 }
689
690 #[doc(hidden)]
692 pub fn for_each_value<V>(&self, mut f: impl FnMut(V) -> Result<()>) -> Result<()>
693 where
694 V: FromLua,
695 {
696 let lua = self.0.lua.lock();
697 let state = lua.state();
698 unsafe {
699 let _sg = StackGuard::new(state);
700 check_stack(state, 4)?;
701
702 lua.push_ref(&self.0);
703 let len = ffi::lua_rawlen(state, -1);
704 for i in 1..=len {
705 ffi::lua_rawgeti(state, -1, i as _);
706 f(V::from_stack(-1, &lua)?)?;
707 ffi::lua_pop(state, 1);
708 }
709 }
710 Ok(())
711 }
712
713 #[doc(hidden)]
715 pub fn raw_seti(&self, idx: usize, value: impl IntoLua) -> Result<()> {
716 let lua = self.0.lua.lock();
717 let state = lua.state();
718 unsafe {
719 #[cfg(feature = "luau")]
720 self.check_readonly_write(&lua)?;
721
722 let _sg = StackGuard::new(state);
723 check_stack(state, 5)?;
724
725 lua.push_ref(&self.0);
726 value.push_into_stack(&lua)?;
727
728 let idx = idx.try_into().unwrap();
729 if lua.unlikely_memory_error() {
730 ffi::lua_rawseti(state, -2, idx);
731 } else {
732 protect_lua!(state, 2, 0, |state| ffi::lua_rawseti(state, -2, idx))?;
733 }
734 }
735 Ok(())
736 }
737
738 #[cfg(feature = "serde")]
739 pub(crate) fn is_array(&self) -> bool {
740 let lua = self.0.lua.lock();
741 let state = lua.state();
742 unsafe {
743 let _sg = StackGuard::new(state);
744 assert_stack(state, 3);
745
746 lua.push_ref(&self.0);
747 if ffi::lua_getmetatable(state, -1) == 0 {
748 return false;
749 }
750 crate::serde::push_array_metatable(state);
751 ffi::lua_rawequal(state, -1, -2) != 0
752 }
753 }
754
755 #[cfg(feature = "luau")]
756 #[inline(always)]
757 fn check_readonly_write(&self, lua: &RawLua) -> Result<()> {
758 if unsafe { ffi::lua_getreadonly(lua.ref_thread(), self.0.index) != 0 } {
759 return Err(Error::runtime("attempt to modify a readonly table"));
760 }
761 Ok(())
762 }
763
764 pub(crate) fn fmt_pretty(
765 &self,
766 fmt: &mut fmt::Formatter,
767 ident: usize,
768 visited: &mut HashSet<*const c_void>,
769 ) -> fmt::Result {
770 visited.insert(self.to_pointer());
771
772 let mut pairs = self.pairs::<Value, Value>().flatten().collect::<Vec<_>>();
774 pairs.sort_by(|(a, _), (b, _)| a.sort_cmp(b));
776 let is_sequence = (pairs.iter().enumerate())
777 .all(|(i, (k, _))| matches!(k, Value::Integer(n) if *n == (i + 1) as Integer));
778 if pairs.is_empty() {
779 return write!(fmt, "{{}}");
780 }
781 writeln!(fmt, "{{")?;
782 if is_sequence {
783 for (_, value) in pairs {
785 write!(fmt, "{}", " ".repeat(ident + 2))?;
786 value.fmt_pretty(fmt, true, ident + 2, visited)?;
787 writeln!(fmt, ",")?;
788 }
789 } else {
790 fn is_simple_key(key: &[u8]) -> bool {
791 key.iter().take(1).all(|c| c.is_ascii_alphabetic() || *c == b'_')
792 && key.iter().all(|c| c.is_ascii_alphanumeric() || *c == b'_')
793 }
794
795 for (key, value) in pairs {
796 match key {
797 Value::String(key) if is_simple_key(&key.as_bytes()) => {
798 write!(fmt, "{}{}", " ".repeat(ident + 2), key.display())?;
799 write!(fmt, " = ")?;
800 }
801 _ => {
802 write!(fmt, "{}[", " ".repeat(ident + 2))?;
803 key.fmt_pretty(fmt, false, ident + 2, visited)?;
804 write!(fmt, "] = ")?;
805 }
806 }
807 value.fmt_pretty(fmt, true, ident + 2, visited)?;
808 writeln!(fmt, ",")?;
809 }
810 }
811 write!(fmt, "{}}}", " ".repeat(ident))
812 }
813}
814
815impl fmt::Debug for Table {
816 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
817 if fmt.alternate() {
818 return self.fmt_pretty(fmt, 0, &mut HashSet::new());
819 }
820 fmt.debug_tuple("Table").field(&self.0).finish()
821 }
822}
823
824impl<T> PartialEq<[T]> for Table
825where
826 T: IntoLua + Clone,
827{
828 fn eq(&self, other: &[T]) -> bool {
829 let lua = self.0.lua.lock();
830 let state = lua.state();
831 unsafe {
832 let _sg = StackGuard::new(state);
833 assert_stack(state, 4);
834
835 lua.push_ref(&self.0);
836
837 let len = ffi::lua_rawlen(state, -1);
838 for i in 0..len {
839 ffi::lua_rawgeti(state, -1, (i + 1) as _);
840 let val = lua.pop_value();
841 if val == Nil {
842 return i == other.len();
843 }
844 match other.get(i).map(|v| v.clone().into_lua(lua.lua())) {
845 Some(Ok(other_val)) if val == other_val => continue,
846 _ => return false,
847 }
848 }
849 }
850 true
851 }
852}
853
854impl<T> PartialEq<&[T]> for Table
855where
856 T: IntoLua + Clone,
857{
858 #[inline]
859 fn eq(&self, other: &&[T]) -> bool {
860 self == *other
861 }
862}
863
864impl<T, const N: usize> PartialEq<[T; N]> for Table
865where
866 T: IntoLua + Clone,
867{
868 #[inline]
869 fn eq(&self, other: &[T; N]) -> bool {
870 self == &other[..]
871 }
872}
873
874impl LuaType for Table {
875 const TYPE_ID: c_int = ffi::LUA_TTABLE;
876}
877
878impl ObjectLike for Table {
879 #[inline]
880 fn get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
881 self.get(key)
882 }
883
884 #[inline]
885 fn set(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
886 self.set(key, value)
887 }
888
889 #[inline]
890 fn call<R>(&self, args: impl IntoLuaMulti) -> Result<R>
891 where
892 R: FromLuaMulti,
893 {
894 Function(self.0.copy()).call(args)
896 }
897
898 #[cfg(feature = "async")]
899 #[inline]
900 fn call_async<R>(&self, args: impl IntoLuaMulti) -> impl Future<Output = Result<R>>
901 where
902 R: FromLuaMulti,
903 {
904 Function(self.0.copy()).call_async(args)
905 }
906
907 #[inline]
908 fn call_method<R>(&self, name: &str, args: impl IntoLuaMulti) -> Result<R>
909 where
910 R: FromLuaMulti,
911 {
912 self.call_function(name, (self, args))
913 }
914
915 #[cfg(feature = "async")]
916 fn call_async_method<R>(&self, name: &str, args: impl IntoLuaMulti) -> impl Future<Output = Result<R>>
917 where
918 R: FromLuaMulti,
919 {
920 self.call_async_function(name, (self, args))
921 }
922
923 #[inline]
924 fn call_function<R: FromLuaMulti>(&self, name: &str, args: impl IntoLuaMulti) -> Result<R> {
925 match self.get(name)? {
926 Value::Function(func) => func.call(args),
927 val => {
928 let msg = format!("attempt to call a {} value (function '{name}')", val.type_name());
929 Err(Error::runtime(msg))
930 }
931 }
932 }
933
934 #[cfg(feature = "async")]
935 #[inline]
936 fn call_async_function<R>(&self, name: &str, args: impl IntoLuaMulti) -> impl Future<Output = Result<R>>
937 where
938 R: FromLuaMulti,
939 {
940 match self.get(name) {
941 Ok(Value::Function(func)) => Either::Left(func.call_async(args)),
942 Ok(val) => {
943 let msg = format!("attempt to call a {} value (function '{name}')", val.type_name());
944 Either::Right(future::ready(Err(Error::RuntimeError(msg))))
945 }
946 Err(err) => Either::Right(future::ready(Err(err))),
947 }
948 }
949
950 #[inline]
951 fn to_string(&self) -> Result<StdString> {
952 Value::Table(Table(self.0.copy())).to_string()
953 }
954}
955
956#[cfg(feature = "serde")]
958pub(crate) struct SerializableTable<'a> {
959 table: &'a Table,
960 options: crate::serde::de::Options,
961 visited: Rc<RefCell<FxHashSet<*const c_void>>>,
962}
963
964#[cfg(feature = "serde")]
965impl Serialize for Table {
966 #[inline]
967 fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
968 SerializableTable::new(self, Default::default(), Default::default()).serialize(serializer)
969 }
970}
971
972#[cfg(feature = "serde")]
973impl<'a> SerializableTable<'a> {
974 #[inline]
975 pub(crate) fn new(
976 table: &'a Table,
977 options: crate::serde::de::Options,
978 visited: Rc<RefCell<FxHashSet<*const c_void>>>,
979 ) -> Self {
980 Self {
981 table,
982 options,
983 visited,
984 }
985 }
986}
987
988#[cfg(feature = "serde")]
989impl Serialize for SerializableTable<'_> {
990 fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
991 where
992 S: Serializer,
993 {
994 use crate::serde::de::{check_value_for_skip, MapPairs, RecursionGuard};
995 use crate::value::SerializableValue;
996
997 let convert_result = |res: Result<()>, serialize_err: Option<S::Error>| match res {
998 Ok(v) => Ok(v),
999 Err(Error::SerializeError(_)) if serialize_err.is_some() => Err(serialize_err.unwrap()),
1000 Err(Error::SerializeError(msg)) => Err(serde::ser::Error::custom(msg)),
1001 Err(err) => Err(serde::ser::Error::custom(err.to_string())),
1002 };
1003
1004 let options = self.options;
1005 let visited = &self.visited;
1006 let _guard = RecursionGuard::new(self.table, visited);
1007
1008 let len = self.table.raw_len();
1010 if len > 0
1011 || self.table.is_array()
1012 || (self.options.encode_empty_tables_as_array && self.table.is_empty())
1013 {
1014 let mut seq = serializer.serialize_seq(Some(len))?;
1015 let mut serialize_err = None;
1016 let res = self.table.for_each_value::<Value>(|value| {
1017 let skip = check_value_for_skip(&value, self.options, visited)
1018 .map_err(|err| Error::SerializeError(err.to_string()))?;
1019 if skip {
1020 return Ok(());
1022 }
1023 seq.serialize_element(&SerializableValue::new(&value, options, Some(visited)))
1024 .map_err(|err| {
1025 serialize_err = Some(err);
1026 Error::SerializeError(StdString::new())
1027 })
1028 });
1029 convert_result(res, serialize_err)?;
1030 return seq.end();
1031 }
1032
1033 let mut map = serializer.serialize_map(None)?;
1035 let mut serialize_err = None;
1036 let mut process_pair = |key, value| {
1037 let skip_key = check_value_for_skip(&key, self.options, visited)
1038 .map_err(|err| Error::SerializeError(err.to_string()))?;
1039 let skip_value = check_value_for_skip(&value, self.options, visited)
1040 .map_err(|err| Error::SerializeError(err.to_string()))?;
1041 if skip_key || skip_value {
1042 return Ok(());
1044 }
1045 map.serialize_entry(
1046 &SerializableValue::new(&key, options, Some(visited)),
1047 &SerializableValue::new(&value, options, Some(visited)),
1048 )
1049 .map_err(|err| {
1050 serialize_err = Some(err);
1051 Error::SerializeError(StdString::new())
1052 })
1053 };
1054
1055 let res = if !self.options.sort_keys {
1056 self.table.for_each(process_pair)
1058 } else {
1059 MapPairs::new(self.table, self.options.sort_keys)
1060 .map_err(serde::ser::Error::custom)?
1061 .try_for_each(|kv| {
1062 let (key, value) = kv?;
1063 process_pair(key, value)
1064 })
1065 };
1066 convert_result(res, serialize_err)?;
1067 map.end()
1068 }
1069}
1070
1071pub struct TablePairs<'a, K, V> {
1077 guard: LuaGuard,
1078 table: &'a Table,
1079 key: Option<Value>,
1080 _phantom: PhantomData<(K, V)>,
1081}
1082
1083impl<K, V> Iterator for TablePairs<'_, K, V>
1084where
1085 K: FromLua,
1086 V: FromLua,
1087{
1088 type Item = Result<(K, V)>;
1089
1090 fn next(&mut self) -> Option<Self::Item> {
1091 if let Some(prev_key) = self.key.take() {
1092 let lua: &RawLua = &self.guard;
1093 let state = lua.state();
1094
1095 let res = (|| unsafe {
1096 let _sg = StackGuard::new(state);
1097 check_stack(state, 5)?;
1098
1099 lua.push_ref(&self.table.0);
1100 lua.push_value(&prev_key)?;
1101
1102 if ffi::lua_next(state, -2) != 0 {
1106 let key = lua.stack_value(-2, None);
1107 Ok(Some((
1108 key.clone(),
1109 K::from_lua(key, lua.lua())?,
1110 V::from_stack(-1, lua)?,
1111 )))
1112 } else {
1113 Ok(None)
1114 }
1115 })();
1116
1117 match res {
1118 Ok(Some((key, ret_key, value))) => {
1119 self.key = Some(key);
1120 Some(Ok((ret_key, value)))
1121 }
1122 Ok(None) => None,
1123 Err(e) => Some(Err(e)),
1124 }
1125 } else {
1126 None
1127 }
1128 }
1129}
1130
1131pub struct TableSequence<'a, V> {
1137 guard: LuaGuard,
1138 table: &'a Table,
1139 index: Integer,
1140 _phantom: PhantomData<V>,
1141}
1142
1143impl<V> Iterator for TableSequence<'_, V>
1144where
1145 V: FromLua,
1146{
1147 type Item = Result<V>;
1148
1149 fn next(&mut self) -> Option<Self::Item> {
1150 let lua: &RawLua = &self.guard;
1151 let state = lua.state();
1152 unsafe {
1153 let _sg = StackGuard::new(state);
1154 if let Err(err) = check_stack(state, 1) {
1155 return Some(Err(err));
1156 }
1157
1158 lua.push_ref(&self.table.0);
1159 match ffi::lua_rawgeti(state, -1, self.index) {
1160 ffi::LUA_TNIL => None,
1161 _ => {
1162 self.index += 1;
1163 Some(V::from_stack(-1, lua))
1164 }
1165 }
1166 }
1167 }
1168}
1169
1170#[cfg(test)]
1171mod assertions {
1172 use super::*;
1173
1174 #[cfg(not(feature = "send"))]
1175 static_assertions::assert_not_impl_any!(Table: Send);
1176 #[cfg(feature = "send")]
1177 static_assertions::assert_impl_all!(Table: Send, Sync);
1178}