1use std::collections::HashSet;
2use std::fmt;
3use std::marker::PhantomData;
4use std::os::raw::c_void;
5use std::string::String as StdString;
6
7#[cfg(feature = "serialize")]
8use {
9 rustc_hash::FxHashSet,
10 serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer},
11 std::{cell::RefCell, rc::Rc, result::Result as StdResult},
12};
13
14use crate::error::{Error, Result};
15use crate::function::Function;
16use crate::state::{LuaGuard, RawLua};
17use crate::traits::ObjectLike;
18use crate::types::{Integer, ValueRef};
19use crate::util::{assert_stack, check_stack, StackGuard};
20use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Nil, Value};
21
22#[cfg(feature = "async")]
23use futures_util::future::{self, Either, Future};
24
25#[derive(Clone)]
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<T: AsRef<Self>>(&self, other: T) -> Result<bool> {
222 let other = other.as_ref();
223 if self == other {
224 return Ok(true);
225 }
226
227 if let Some(mt) = self.get_metatable() {
231 if mt.contains_key("__eq")? {
232 return mt.get::<Function>("__eq")?.call((self, other));
233 }
234 }
235 if let Some(mt) = other.get_metatable() {
236 if mt.contains_key("__eq")? {
237 return mt.get::<Function>("__eq")?.call((self, other));
238 }
239 }
240
241 Ok(false)
242 }
243
244 pub fn raw_set(&self, key: impl IntoLua, value: impl IntoLua) -> Result<()> {
246 #[cfg(feature = "luau")]
247 self.check_readonly_write()?;
248
249 let lua = self.0.lua.lock();
250 let state = lua.state();
251 unsafe {
252 let _sg = StackGuard::new(state);
253 check_stack(state, 5)?;
254
255 lua.push_ref(&self.0);
256 key.push_into_stack(&lua)?;
257 value.push_into_stack(&lua)?;
258
259 if lua.unlikely_memory_error() {
260 ffi::lua_rawset(state, -3);
261 ffi::lua_pop(state, 1);
262 Ok(())
263 } else {
264 protect_lua!(state, 3, 0, fn(state) ffi::lua_rawset(state, -3))
265 }
266 }
267 }
268
269 pub fn raw_get<V: FromLua>(&self, key: impl IntoLua) -> Result<V> {
271 let lua = self.0.lua.lock();
272 let state = lua.state();
273 unsafe {
274 let _sg = StackGuard::new(state);
275 check_stack(state, 3)?;
276
277 lua.push_ref(&self.0);
278 key.push_into_stack(&lua)?;
279 ffi::lua_rawget(state, -2);
280
281 V::from_stack(-1, &lua)
282 }
283 }
284
285 pub fn raw_insert(&self, idx: Integer, value: impl IntoLua) -> Result<()> {
288 let size = self.raw_len() as Integer;
289 if idx < 1 || idx > size + 1 {
290 return Err(Error::runtime("index out of bounds"));
291 }
292
293 let lua = self.0.lua.lock();
294 let state = lua.state();
295 unsafe {
296 let _sg = StackGuard::new(state);
297 check_stack(state, 5)?;
298
299 lua.push_ref(&self.0);
300 value.push_into_stack(&lua)?;
301 protect_lua!(state, 2, 0, |state| {
302 for i in (idx..=size).rev() {
303 ffi::lua_rawgeti(state, -2, i);
305 ffi::lua_rawseti(state, -3, i + 1);
306 }
307 ffi::lua_rawseti(state, -2, idx)
308 })
309 }
310 }
311
312 pub fn raw_push(&self, value: impl IntoLua) -> Result<()> {
314 #[cfg(feature = "luau")]
315 self.check_readonly_write()?;
316
317 let lua = self.0.lua.lock();
318 let state = lua.state();
319 unsafe {
320 let _sg = StackGuard::new(state);
321 check_stack(state, 4)?;
322
323 lua.push_ref(&self.0);
324 value.push_into_stack(&lua)?;
325
326 unsafe fn callback(state: *mut ffi::lua_State) {
327 let len = ffi::lua_rawlen(state, -2) as Integer;
328 ffi::lua_rawseti(state, -2, len + 1);
329 }
330
331 if lua.unlikely_memory_error() {
332 callback(state);
333 } else {
334 protect_lua!(state, 2, 0, fn(state) callback(state))?;
335 }
336 }
337 Ok(())
338 }
339
340 pub fn raw_pop<V: FromLua>(&self) -> Result<V> {
342 #[cfg(feature = "luau")]
343 self.check_readonly_write()?;
344
345 let lua = self.0.lua.lock();
346 let state = lua.state();
347 unsafe {
348 let _sg = StackGuard::new(state);
349 check_stack(state, 3)?;
350
351 lua.push_ref(&self.0);
352 let len = ffi::lua_rawlen(state, -1) as Integer;
353 ffi::lua_rawgeti(state, -1, len);
354 ffi::lua_pushnil(state);
356 ffi::lua_rawseti(state, -3, len);
357
358 V::from_stack(-1, &lua)
359 }
360 }
361
362 pub fn raw_remove(&self, key: impl IntoLua) -> Result<()> {
370 let lua = self.0.lua.lock();
371 let state = lua.state();
372 let key = key.into_lua(lua.lua())?;
373 match key {
374 Value::Integer(idx) => {
375 let size = self.raw_len() as Integer;
376 if idx < 1 || idx > size {
377 return Err(Error::runtime("index out of bounds"));
378 }
379 unsafe {
380 let _sg = StackGuard::new(state);
381 check_stack(state, 4)?;
382
383 lua.push_ref(&self.0);
384 protect_lua!(state, 1, 0, |state| {
385 for i in idx..size {
386 ffi::lua_rawgeti(state, -1, i + 1);
387 ffi::lua_rawseti(state, -2, i);
388 }
389 ffi::lua_pushnil(state);
390 ffi::lua_rawseti(state, -2, size);
391 })
392 }
393 }
394 _ => self.raw_set(key, Nil),
395 }
396 }
397
398 pub fn clear(&self) -> Result<()> {
403 #[cfg(feature = "luau")]
404 self.check_readonly_write()?;
405
406 let lua = self.0.lua.lock();
407 unsafe {
408 #[cfg(feature = "luau")]
409 ffi::lua_cleartable(lua.ref_thread(), self.0.index);
410
411 #[cfg(not(feature = "luau"))]
412 {
413 let state = lua.state();
414 check_stack(state, 4)?;
415
416 lua.push_ref(&self.0);
417
418 for i in 1..=ffi::lua_rawlen(state, -1) {
420 ffi::lua_pushnil(state);
421 ffi::lua_rawseti(state, -2, i as Integer);
422 }
423
424 ffi::lua_pushnil(state);
427 while ffi::lua_next(state, -2) != 0 {
428 ffi::lua_pop(state, 1); ffi::lua_pushvalue(state, -1); ffi::lua_pushnil(state);
431 ffi::lua_rawset(state, -4);
432 }
433 }
434 }
435
436 Ok(())
437 }
438
439 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 if self.raw_len() != 0 {
473 return false;
474 }
475
476 let lua = self.0.lua.lock();
478 let state = lua.state();
479 unsafe {
480 let _sg = StackGuard::new(state);
481 assert_stack(state, 4);
482
483 lua.push_ref(&self.0);
484 ffi::lua_pushnil(state);
485 if ffi::lua_next(state, -2) != 0 {
486 return false;
487 }
488 }
489
490 true
491 }
492
493 pub fn get_metatable(&self) -> Option<Table> {
497 let lua = self.0.lua.lock();
498 let state = lua.state();
499 unsafe {
500 let _sg = StackGuard::new(state);
501 assert_stack(state, 2);
502
503 lua.push_ref(&self.0);
504 if ffi::lua_getmetatable(state, -1) == 0 {
505 None
506 } else {
507 Some(Table(lua.pop_ref()))
508 }
509 }
510 }
511
512 pub fn set_metatable(&self, metatable: Option<Table>) {
517 #[cfg(feature = "luau")]
519 if self.is_readonly() {
520 panic!("attempt to modify a readonly table");
521 }
522
523 let lua = self.0.lua.lock();
524 let state = lua.state();
525 unsafe {
526 let _sg = StackGuard::new(state);
527 assert_stack(state, 2);
528
529 lua.push_ref(&self.0);
530 if let Some(metatable) = metatable {
531 lua.push_ref(&metatable.0);
532 } else {
533 ffi::lua_pushnil(state);
534 }
535 ffi::lua_setmetatable(state, -2);
536 }
537 }
538
539 #[doc(hidden)]
541 #[inline]
542 pub fn has_metatable(&self) -> bool {
543 let lua = self.0.lua.lock();
544 let ref_thread = lua.ref_thread();
545 unsafe {
546 if ffi::lua_getmetatable(ref_thread, self.0.index) != 0 {
547 ffi::lua_pop(ref_thread, 1);
548 return true;
549 }
550 }
551 false
552 }
553
554 #[cfg(any(feature = "luau", doc))]
558 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
559 pub fn set_readonly(&self, enabled: bool) {
560 let lua = self.0.lua.lock();
561 let ref_thread = lua.ref_thread();
562 unsafe {
563 ffi::lua_setreadonly(ref_thread, self.0.index, enabled as _);
564 if !enabled {
565 ffi::lua_setsafeenv(ref_thread, self.0.index, 0);
567 }
568 }
569 }
570
571 #[cfg(any(feature = "luau", doc))]
575 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
576 pub fn is_readonly(&self) -> bool {
577 let lua = self.0.lua.lock();
578 let ref_thread = lua.ref_thread();
579 unsafe { ffi::lua_getreadonly(ref_thread, self.0.index) != 0 }
580 }
581
582 #[inline]
589 pub fn to_pointer(&self) -> *const c_void {
590 self.0.to_pointer()
591 }
592
593 pub fn pairs<K: FromLua, V: FromLua>(&self) -> TablePairs<K, V> {
621 TablePairs {
622 guard: self.0.lua.lock(),
623 table: self,
624 key: Some(Nil),
625 _phantom: PhantomData,
626 }
627 }
628
629 pub fn for_each<K, V>(&self, mut f: impl FnMut(K, V) -> Result<()>) -> Result<()>
634 where
635 K: FromLua,
636 V: FromLua,
637 {
638 let lua = self.0.lua.lock();
639 let state = lua.state();
640 unsafe {
641 let _sg = StackGuard::new(state);
642 check_stack(state, 5)?;
643
644 lua.push_ref(&self.0);
645 ffi::lua_pushnil(state);
646 while ffi::lua_next(state, -2) != 0 {
647 let k = K::from_stack(-2, &lua)?;
648 let v = V::from_stack(-1, &lua)?;
649 f(k, v)?;
650 ffi::lua_pop(state, 1);
652 }
653 }
654 Ok(())
655 }
656
657 pub fn sequence_values<V: FromLua>(&self) -> TableSequence<V> {
690 TableSequence {
691 guard: self.0.lua.lock(),
692 table: self,
693 index: 1,
694 _phantom: PhantomData,
695 }
696 }
697
698 #[cfg(feature = "serialize")]
699 pub(crate) fn for_each_value<V>(&self, mut f: impl FnMut(V) -> Result<()>) -> Result<()>
700 where
701 V: FromLua,
702 {
703 let lua = self.0.lua.lock();
704 let state = lua.state();
705 unsafe {
706 let _sg = StackGuard::new(state);
707 check_stack(state, 4)?;
708
709 lua.push_ref(&self.0);
710 let len = ffi::lua_rawlen(state, -1);
711 for i in 1..=len {
712 ffi::lua_rawgeti(state, -1, i as _);
713 f(V::from_stack(-1, &lua)?)?;
714 ffi::lua_pop(state, 1);
715 }
716 }
717 Ok(())
718 }
719
720 #[doc(hidden)]
722 pub fn raw_seti(&self, idx: usize, value: impl IntoLua) -> Result<()> {
723 #[cfg(feature = "luau")]
724 self.check_readonly_write()?;
725
726 let lua = self.0.lua.lock();
727 let state = lua.state();
728 unsafe {
729 let _sg = StackGuard::new(state);
730 check_stack(state, 5)?;
731
732 lua.push_ref(&self.0);
733 value.push_into_stack(&lua)?;
734
735 let idx = idx.try_into().unwrap();
736 if lua.unlikely_memory_error() {
737 ffi::lua_rawseti(state, -2, idx);
738 } else {
739 protect_lua!(state, 2, 0, |state| ffi::lua_rawseti(state, -2, idx))?;
740 }
741 }
742 Ok(())
743 }
744
745 #[cfg(feature = "serialize")]
746 pub(crate) fn is_array(&self) -> bool {
747 let lua = self.0.lua.lock();
748 let state = lua.state();
749 unsafe {
750 let _sg = StackGuard::new(state);
751 assert_stack(state, 3);
752
753 lua.push_ref(&self.0);
754 if ffi::lua_getmetatable(state, -1) == 0 {
755 return false;
756 }
757 crate::serde::push_array_metatable(state);
758 ffi::lua_rawequal(state, -1, -2) != 0
759 }
760 }
761
762 #[cfg(feature = "luau")]
763 #[inline(always)]
764 pub(crate) fn check_readonly_write(&self) -> Result<()> {
765 if self.is_readonly() {
766 return Err(Error::runtime("attempt to modify a readonly table"));
767 }
768 Ok(())
769 }
770
771 pub(crate) fn fmt_pretty(
772 &self,
773 fmt: &mut fmt::Formatter,
774 ident: usize,
775 visited: &mut HashSet<*const c_void>,
776 ) -> fmt::Result {
777 visited.insert(self.to_pointer());
778
779 let mut pairs = self.pairs::<Value, Value>().flatten().collect::<Vec<_>>();
781 pairs.sort_by(|(a, _), (b, _)| a.cmp(b));
783 if pairs.is_empty() {
784 return write!(fmt, "{{}}");
785 }
786 writeln!(fmt, "{{")?;
787 for (key, value) in pairs {
788 write!(fmt, "{}[", " ".repeat(ident + 2))?;
789 key.fmt_pretty(fmt, false, ident + 2, visited)?;
790 write!(fmt, "] = ")?;
791 value.fmt_pretty(fmt, true, ident + 2, visited)?;
792 writeln!(fmt, ",")?;
793 }
794 write!(fmt, "{}}}", " ".repeat(ident))
795 }
796}
797
798impl fmt::Debug for Table {
799 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
800 if fmt.alternate() {
801 return self.fmt_pretty(fmt, 0, &mut HashSet::new());
802 }
803 fmt.write_fmt(format_args!("Table({:?})", self.0))
804 }
805}
806
807impl PartialEq for Table {
808 fn eq(&self, other: &Self) -> bool {
809 self.0 == other.0
810 }
811}
812
813impl AsRef<Table> for Table {
814 #[inline]
815 fn as_ref(&self) -> &Self {
816 self
817 }
818}
819
820impl<T> PartialEq<[T]> for Table
821where
822 T: IntoLua + Clone,
823{
824 fn eq(&self, other: &[T]) -> bool {
825 let lua = self.0.lua.lock();
826 let state = lua.state();
827 unsafe {
828 let _sg = StackGuard::new(state);
829 assert_stack(state, 4);
830
831 lua.push_ref(&self.0);
832
833 let len = ffi::lua_rawlen(state, -1);
834 for i in 0..len {
835 ffi::lua_rawgeti(state, -1, (i + 1) as _);
836 let val = lua.pop_value();
837 if val == Nil {
838 return i == other.len();
839 }
840 match other.get(i).map(|v| v.clone().into_lua(lua.lua())) {
841 Some(Ok(other_val)) if val == other_val => continue,
842 _ => return false,
843 }
844 }
845 }
846 true
847 }
848}
849
850impl<T> PartialEq<&[T]> for Table
851where
852 T: IntoLua + Clone,
853{
854 #[inline]
855 fn eq(&self, other: &&[T]) -> bool {
856 self == *other
857 }
858}
859
860impl<T, const N: usize> PartialEq<[T; N]> for Table
861where
862 T: IntoLua + Clone,
863{
864 #[inline]
865 fn eq(&self, other: &[T; N]) -> bool {
866 self == &other[..]
867 }
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) -> impl Future<Output = Result<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) -> impl Future<Output = Result<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) -> impl Future<Output = Result<R>>
929 where
930 R: FromLuaMulti,
931 {
932 match self.get(name) {
933 Ok(Value::Function(func)) => Either::Left(func.call_async(args)),
934 Ok(val) => {
935 let msg = format!("attempt to call a {} value (function '{name}')", val.type_name());
936 Either::Right(future::ready(Err(Error::RuntimeError(msg))))
937 }
938 Err(err) => Either::Right(future::ready(Err(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 = "serialize")]
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 = "serialize")]
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 = "serialize")]
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 = "serialize")]
981impl<'a> Serialize for SerializableTable<'a> {
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 || self.table.is_array() {
1003 let mut seq = serializer.serialize_seq(Some(len))?;
1004 let mut serialize_err = None;
1005 let res = self.table.for_each_value::<Value>(|value| {
1006 let skip = check_value_for_skip(&value, self.options, visited)
1007 .map_err(|err| Error::SerializeError(err.to_string()))?;
1008 if skip {
1009 return Ok(());
1011 }
1012 seq.serialize_element(&SerializableValue::new(&value, options, Some(visited)))
1013 .map_err(|err| {
1014 serialize_err = Some(err);
1015 Error::SerializeError(StdString::new())
1016 })
1017 });
1018 convert_result(res, serialize_err)?;
1019 return seq.end();
1020 }
1021
1022 let mut map = serializer.serialize_map(None)?;
1024 let mut serialize_err = None;
1025 let mut process_pair = |key, value| {
1026 let skip_key = check_value_for_skip(&key, self.options, visited)
1027 .map_err(|err| Error::SerializeError(err.to_string()))?;
1028 let skip_value = check_value_for_skip(&value, self.options, visited)
1029 .map_err(|err| Error::SerializeError(err.to_string()))?;
1030 if skip_key || skip_value {
1031 return Ok(());
1033 }
1034 map.serialize_entry(
1035 &SerializableValue::new(&key, options, Some(visited)),
1036 &SerializableValue::new(&value, options, Some(visited)),
1037 )
1038 .map_err(|err| {
1039 serialize_err = Some(err);
1040 Error::SerializeError(StdString::new())
1041 })
1042 };
1043
1044 let res = if !self.options.sort_keys {
1045 self.table.for_each(process_pair)
1047 } else {
1048 MapPairs::new(self.table, self.options.sort_keys)
1049 .map_err(serde::ser::Error::custom)?
1050 .try_for_each(|kv| {
1051 let (key, value) = kv?;
1052 process_pair(key, value)
1053 })
1054 };
1055 convert_result(res, serialize_err)?;
1056 map.end()
1057 }
1058}
1059
1060pub struct TablePairs<'a, K, V> {
1066 guard: LuaGuard,
1067 table: &'a Table,
1068 key: Option<Value>,
1069 _phantom: PhantomData<(K, V)>,
1070}
1071
1072impl<'a, K, V> Iterator for TablePairs<'a, K, V>
1073where
1074 K: FromLua,
1075 V: FromLua,
1076{
1077 type Item = Result<(K, V)>;
1078
1079 fn next(&mut self) -> Option<Self::Item> {
1080 if let Some(prev_key) = self.key.take() {
1081 let lua: &RawLua = &self.guard;
1082 let state = lua.state();
1083
1084 let res = (|| unsafe {
1085 let _sg = StackGuard::new(state);
1086 check_stack(state, 5)?;
1087
1088 lua.push_ref(&self.table.0);
1089 lua.push_value(&prev_key)?;
1090
1091 if ffi::lua_next(state, -2) != 0 {
1095 let key = lua.stack_value(-2, None);
1096 Ok(Some((
1097 key.clone(),
1098 K::from_lua(key, lua.lua())?,
1099 V::from_stack(-1, lua)?,
1100 )))
1101 } else {
1102 Ok(None)
1103 }
1104 })();
1105
1106 match res {
1107 Ok(Some((key, ret_key, value))) => {
1108 self.key = Some(key);
1109 Some(Ok((ret_key, value)))
1110 }
1111 Ok(None) => None,
1112 Err(e) => Some(Err(e)),
1113 }
1114 } else {
1115 None
1116 }
1117 }
1118}
1119
1120pub struct TableSequence<'a, V> {
1126 guard: LuaGuard,
1127 table: &'a Table,
1128 index: Integer,
1129 _phantom: PhantomData<V>,
1130}
1131
1132impl<'a, V> Iterator for TableSequence<'a, V>
1133where
1134 V: FromLua,
1135{
1136 type Item = Result<V>;
1137
1138 fn next(&mut self) -> Option<Self::Item> {
1139 let lua: &RawLua = &self.guard;
1140 let state = lua.state();
1141 unsafe {
1142 let _sg = StackGuard::new(state);
1143 if let Err(err) = check_stack(state, 1) {
1144 return Some(Err(err));
1145 }
1146
1147 lua.push_ref(&self.table.0);
1148 match ffi::lua_rawgeti(state, -1, self.index) {
1149 ffi::LUA_TNIL => None,
1150 _ => {
1151 self.index += 1;
1152 Some(V::from_stack(-1, lua))
1153 }
1154 }
1155 }
1156 }
1157}
1158
1159#[cfg(test)]
1160mod assertions {
1161 use super::*;
1162
1163 #[cfg(not(feature = "send"))]
1164 static_assertions::assert_not_impl_any!(Table: Send);
1165 #[cfg(feature = "send")]
1166 static_assertions::assert_impl_all!(Table: Send, Sync);
1167}