1use std::collections::HashSet;
2use std::fmt;
3use std::marker::PhantomData;
4use std::os::raw::c_void;
5
6#[cfg(feature = "serialize")]
7use {
8 rustc_hash::FxHashSet,
9 serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer},
10 std::{cell::RefCell, rc::Rc, result::Result as StdResult},
11};
12
13use crate::error::{Error, Result};
14use crate::function::Function;
15use crate::private::Sealed;
16use crate::types::{Integer, LuaRef};
17use crate::util::{assert_stack, check_stack, StackGuard};
18use crate::value::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Nil, Value};
19
20#[cfg(feature = "async")]
21use futures_util::future::{self, LocalBoxFuture};
22
23#[derive(Clone)]
25pub struct Table<'lua>(pub(crate) LuaRef<'lua>);
26
27#[cfg(feature = "unstable")]
35#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
36#[derive(Clone, Debug)]
37pub struct OwnedTable(pub(crate) crate::types::LuaOwnedRef);
38
39#[cfg(feature = "unstable")]
40impl OwnedTable {
41 #[cfg_attr(feature = "send", allow(unused))]
43 pub const fn to_ref(&self) -> Table {
44 Table(self.0.to_ref())
45 }
46}
47
48impl<'lua> Table<'lua> {
49 pub fn set<K: IntoLua<'lua>, V: IntoLua<'lua>>(&self, key: K, value: V) -> Result<()> {
83 if !self.has_metatable() {
85 return self.raw_set(key, value);
86 }
87
88 let lua = self.0.lua;
89 let state = lua.state();
90 unsafe {
91 let _sg = StackGuard::new(state);
92 check_stack(state, 5)?;
93
94 lua.push_ref(&self.0);
95 key.push_into_stack(lua)?;
96 value.push_into_stack(lua)?;
97 protect_lua!(state, 3, 0, fn(state) ffi::lua_settable(state, -3))
98 }
99 }
100
101 pub fn get<K: IntoLua<'lua>, V: FromLua<'lua>>(&self, key: K) -> Result<V> {
126 if !self.has_metatable() {
128 return self.raw_get(key);
129 }
130
131 let lua = self.0.lua;
132 let state = lua.state();
133 unsafe {
134 let _sg = StackGuard::new(state);
135 check_stack(state, 4)?;
136
137 lua.push_ref(&self.0);
138 key.push_into_stack(lua)?;
139 protect_lua!(state, 2, 1, fn(state) ffi::lua_gettable(state, -2))?;
140
141 V::from_stack(-1, lua)
142 }
143 }
144
145 pub fn contains_key<K: IntoLua<'lua>>(&self, key: K) -> Result<bool> {
149 Ok(self.get::<_, Value>(key)? != Value::Nil)
150 }
151
152 pub fn push<V: IntoLua<'lua>>(&self, value: V) -> Result<()> {
156 if !self.has_metatable() {
158 return self.raw_push(value);
159 }
160
161 let lua = self.0.lua;
162 let state = lua.state();
163 unsafe {
164 let _sg = StackGuard::new(state);
165 check_stack(state, 4)?;
166
167 lua.push_ref(&self.0);
168 value.push_into_stack(lua)?;
169 protect_lua!(state, 2, 0, fn(state) {
170 let len = ffi::luaL_len(state, -2) as Integer;
171 ffi::lua_seti(state, -2, len + 1);
172 })?
173 }
174 Ok(())
175 }
176
177 pub fn pop<V: FromLua<'lua>>(&self) -> Result<V> {
181 if !self.has_metatable() {
183 return self.raw_pop();
184 }
185
186 let lua = self.0.lua;
187 let state = lua.state();
188 unsafe {
189 let _sg = StackGuard::new(state);
190 check_stack(state, 4)?;
191
192 lua.push_ref(&self.0);
193 protect_lua!(state, 1, 1, fn(state) {
194 let len = ffi::luaL_len(state, -1) as Integer;
195 ffi::lua_geti(state, -1, len);
196 ffi::lua_pushnil(state);
197 ffi::lua_seti(state, -3, len);
198 })?;
199 V::from_stack(-1, lua)
200 }
201 }
202
203 pub fn equals<T: AsRef<Self>>(&self, other: T) -> Result<bool> {
233 let other = other.as_ref();
234 if self == other {
235 return Ok(true);
236 }
237
238 if let Some(mt) = self.get_metatable() {
242 if mt.contains_key("__eq")? {
243 return mt
244 .get::<_, Function>("__eq")?
245 .call((self.clone(), other.clone()));
246 }
247 }
248 if let Some(mt) = other.get_metatable() {
249 if mt.contains_key("__eq")? {
250 return mt
251 .get::<_, Function>("__eq")?
252 .call((self.clone(), other.clone()));
253 }
254 }
255
256 Ok(false)
257 }
258
259 pub fn raw_set<K: IntoLua<'lua>, V: IntoLua<'lua>>(&self, key: K, value: V) -> Result<()> {
261 #[cfg(feature = "luau")]
262 self.check_readonly_write()?;
263
264 let lua = self.0.lua;
265 let state = lua.state();
266 unsafe {
267 let _sg = StackGuard::new(state);
268 check_stack(state, 5)?;
269
270 lua.push_ref(&self.0);
271 key.push_into_stack(lua)?;
272 value.push_into_stack(lua)?;
273
274 if lua.unlikely_memory_error() {
275 ffi::lua_rawset(state, -3);
276 ffi::lua_pop(state, 1);
277 Ok(())
278 } else {
279 protect_lua!(state, 3, 0, fn(state) ffi::lua_rawset(state, -3))
280 }
281 }
282 }
283
284 pub fn raw_get<K: IntoLua<'lua>, V: FromLua<'lua>>(&self, key: K) -> Result<V> {
286 let lua = self.0.lua;
287 let state = lua.state();
288 unsafe {
289 let _sg = StackGuard::new(state);
290 check_stack(state, 3)?;
291
292 lua.push_ref(&self.0);
293 key.push_into_stack(lua)?;
294 ffi::lua_rawget(state, -2);
295
296 V::from_stack(-1, lua)
297 }
298 }
299
300 pub fn raw_insert<V: IntoLua<'lua>>(&self, idx: Integer, value: V) -> Result<()> {
303 let size = self.raw_len() as Integer;
304 if idx < 1 || idx > size + 1 {
305 return Err(Error::runtime("index out of bounds"));
306 }
307
308 let lua = self.0.lua;
309 let state = lua.state();
310 unsafe {
311 let _sg = StackGuard::new(state);
312 check_stack(state, 5)?;
313
314 lua.push_ref(&self.0);
315 value.push_into_stack(lua)?;
316 protect_lua!(state, 2, 0, |state| {
317 for i in (idx..=size).rev() {
318 ffi::lua_rawgeti(state, -2, i);
320 ffi::lua_rawseti(state, -3, i + 1);
321 }
322 ffi::lua_rawseti(state, -2, idx)
323 })
324 }
325 }
326
327 pub fn raw_push<V: IntoLua<'lua>>(&self, value: V) -> Result<()> {
329 #[cfg(feature = "luau")]
330 self.check_readonly_write()?;
331
332 let lua = self.0.lua;
333 let state = lua.state();
334 unsafe {
335 let _sg = StackGuard::new(state);
336 check_stack(state, 4)?;
337
338 lua.push_ref(&self.0);
339 value.push_into_stack(lua)?;
340
341 unsafe fn callback(state: *mut ffi::lua_State) {
342 let len = ffi::lua_rawlen(state, -2) as Integer;
343 ffi::lua_rawseti(state, -2, len + 1);
344 }
345
346 if lua.unlikely_memory_error() {
347 callback(state);
348 } else {
349 protect_lua!(state, 2, 0, fn(state) callback(state))?;
350 }
351 }
352 Ok(())
353 }
354
355 pub fn raw_pop<V: FromLua<'lua>>(&self) -> Result<V> {
357 #[cfg(feature = "luau")]
358 self.check_readonly_write()?;
359
360 let lua = self.0.lua;
361 let state = lua.state();
362 unsafe {
363 let _sg = StackGuard::new(state);
364 check_stack(state, 3)?;
365
366 lua.push_ref(&self.0);
367 let len = ffi::lua_rawlen(state, -1) as Integer;
368 ffi::lua_rawgeti(state, -1, len);
369 ffi::lua_pushnil(state);
371 ffi::lua_rawseti(state, -3, len);
372
373 V::from_stack(-1, lua)
374 }
375 }
376
377 pub fn raw_remove<K: IntoLua<'lua>>(&self, key: K) -> Result<()> {
385 let lua = self.0.lua;
386 let state = lua.state();
387 let key = key.into_lua(lua)?;
388 match key {
389 Value::Integer(idx) => {
390 let size = self.raw_len() as Integer;
391 if idx < 1 || idx > size {
392 return Err(Error::runtime("index out of bounds"));
393 }
394 unsafe {
395 let _sg = StackGuard::new(state);
396 check_stack(state, 4)?;
397
398 lua.push_ref(&self.0);
399 protect_lua!(state, 1, 0, |state| {
400 for i in idx..size {
401 ffi::lua_rawgeti(state, -1, i + 1);
402 ffi::lua_rawseti(state, -2, i);
403 }
404 ffi::lua_pushnil(state);
405 ffi::lua_rawseti(state, -2, size);
406 })
407 }
408 }
409 _ => self.raw_set(key, Nil),
410 }
411 }
412
413 pub fn clear(&self) -> Result<()> {
418 #[cfg(feature = "luau")]
419 self.check_readonly_write()?;
420
421 let lua = self.0.lua;
422 unsafe {
423 #[cfg(feature = "luau")]
424 ffi::lua_cleartable(lua.ref_thread(), self.0.index);
425
426 #[cfg(not(feature = "luau"))]
427 {
428 let state = lua.state();
429 check_stack(state, 4)?;
430
431 lua.push_ref(&self.0);
432
433 for i in 1..=ffi::lua_rawlen(state, -1) {
435 ffi::lua_pushnil(state);
436 ffi::lua_rawseti(state, -2, i as Integer);
437 }
438
439 ffi::lua_pushnil(state);
442 while ffi::lua_next(state, -2) != 0 {
443 ffi::lua_pop(state, 1); ffi::lua_pushvalue(state, -1); ffi::lua_pushnil(state);
446 ffi::lua_rawset(state, -4);
447 }
448 }
449 }
450
451 Ok(())
452 }
453
454 pub fn len(&self) -> Result<Integer> {
460 if !self.has_metatable() {
462 return Ok(self.raw_len() as Integer);
463 }
464
465 let lua = self.0.lua;
466 let state = lua.state();
467 unsafe {
468 let _sg = StackGuard::new(state);
469 check_stack(state, 4)?;
470
471 lua.push_ref(&self.0);
472 protect_lua!(state, 1, 0, |state| ffi::luaL_len(state, -1))
473 }
474 }
475
476 pub fn raw_len(&self) -> usize {
478 let ref_thread = self.0.lua.ref_thread();
479 unsafe { ffi::lua_rawlen(ref_thread, self.0.index) }
480 }
481
482 pub fn is_empty(&self) -> bool {
486 if self.raw_len() != 0 {
488 return false;
489 }
490
491 let lua = self.0.lua;
493 let state = lua.state();
494 unsafe {
495 let _sg = StackGuard::new(state);
496 assert_stack(state, 4);
497
498 lua.push_ref(&self.0);
499 ffi::lua_pushnil(state);
500 if ffi::lua_next(state, -2) != 0 {
501 return false;
502 }
503 }
504
505 true
506 }
507
508 pub fn get_metatable(&self) -> Option<Table<'lua>> {
512 let lua = self.0.lua;
513 let state = lua.state();
514 unsafe {
515 let _sg = StackGuard::new(state);
516 assert_stack(state, 2);
517
518 lua.push_ref(&self.0);
519 if ffi::lua_getmetatable(state, -1) == 0 {
520 None
521 } else {
522 Some(Table(lua.pop_ref()))
523 }
524 }
525 }
526
527 pub fn set_metatable(&self, metatable: Option<Table<'lua>>) {
532 #[cfg(feature = "luau")]
534 if self.is_readonly() {
535 panic!("attempt to modify a readonly table");
536 }
537
538 let lua = self.0.lua;
539 let state = lua.state();
540 unsafe {
541 let _sg = StackGuard::new(state);
542 assert_stack(state, 2);
543
544 lua.push_ref(&self.0);
545 if let Some(metatable) = metatable {
546 lua.push_ref(&metatable.0);
547 } else {
548 ffi::lua_pushnil(state);
549 }
550 ffi::lua_setmetatable(state, -2);
551 }
552 }
553
554 #[doc(hidden)]
556 #[inline]
557 pub fn has_metatable(&self) -> bool {
558 let ref_thread = self.0.lua.ref_thread();
559 unsafe {
560 if ffi::lua_getmetatable(ref_thread, self.0.index) != 0 {
561 ffi::lua_pop(ref_thread, 1);
562 return true;
563 }
564 }
565 false
566 }
567
568 #[cfg(any(feature = "luau", doc))]
572 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
573 pub fn set_readonly(&self, enabled: bool) {
574 let ref_thread = self.0.lua.ref_thread();
575 unsafe {
576 ffi::lua_setreadonly(ref_thread, self.0.index, enabled as _);
577 if !enabled {
578 ffi::lua_setsafeenv(ref_thread, self.0.index, 0);
580 }
581 }
582 }
583
584 #[cfg(any(feature = "luau", doc))]
588 #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
589 pub fn is_readonly(&self) -> bool {
590 let ref_thread = self.0.lua.ref_thread();
591 unsafe { ffi::lua_getreadonly(ref_thread, self.0.index) != 0 }
592 }
593
594 #[inline]
601 pub fn to_pointer(&self) -> *const c_void {
602 self.0.to_pointer()
603 }
604
605 #[cfg(all(feature = "unstable", any(not(feature = "send"), doc)))]
607 #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", not(feature = "send")))))]
608 #[inline]
609 pub fn into_owned(self) -> OwnedTable {
610 OwnedTable(self.0.into_owned())
611 }
612
613 pub fn pairs<K: FromLua<'lua>, V: FromLua<'lua>>(self) -> TablePairs<'lua, K, V> {
647 TablePairs {
648 table: self.0,
649 key: Some(Nil),
650 _phantom: PhantomData,
651 }
652 }
653
654 pub fn for_each<K, V>(&self, mut f: impl FnMut(K, V) -> Result<()>) -> Result<()>
659 where
660 K: FromLua<'lua>,
661 V: FromLua<'lua>,
662 {
663 let lua = self.0.lua;
664 let state = lua.state();
665 unsafe {
666 let _sg = StackGuard::new(state);
667 check_stack(state, 5)?;
668
669 lua.push_ref(&self.0);
670 ffi::lua_pushnil(state);
671 while ffi::lua_next(state, -2) != 0 {
672 let k = K::from_stack(-2, lua)?;
673 let v = V::from_stack(-1, lua)?;
674 f(k, v)?;
675 ffi::lua_pop(state, 1);
677 }
678 }
679 Ok(())
680 }
681
682 pub fn sequence_values<V: FromLua<'lua>>(self) -> TableSequence<'lua, V> {
721 TableSequence {
722 table: self.0,
723 index: 1,
724 _phantom: PhantomData,
725 }
726 }
727
728 #[doc(hidden)]
729 #[deprecated(since = "0.9.0", note = "use `sequence_values` instead")]
730 pub fn raw_sequence_values<V: FromLua<'lua>>(self) -> TableSequence<'lua, V> {
731 self.sequence_values()
732 }
733
734 #[cfg(feature = "serialize")]
735 pub(crate) fn for_each_value<V>(&self, mut f: impl FnMut(V) -> Result<()>) -> Result<()>
736 where
737 V: FromLua<'lua>,
738 {
739 let lua = self.0.lua;
740 let state = lua.state();
741 unsafe {
742 let _sg = StackGuard::new(state);
743 check_stack(state, 4)?;
744
745 lua.push_ref(&self.0);
746 let len = ffi::lua_rawlen(state, -1);
747 for i in 1..=len {
748 ffi::lua_rawgeti(state, -1, i as _);
749 f(V::from_stack(-1, lua)?)?;
750 ffi::lua_pop(state, 1);
751 }
752 }
753 Ok(())
754 }
755
756 #[doc(hidden)]
758 pub fn raw_seti<V: IntoLua<'lua>>(&self, idx: usize, value: V) -> Result<()> {
759 #[cfg(feature = "luau")]
760 self.check_readonly_write()?;
761
762 let lua = self.0.lua;
763 let state = lua.state();
764 unsafe {
765 let _sg = StackGuard::new(state);
766 check_stack(state, 5)?;
767
768 lua.push_ref(&self.0);
769 value.push_into_stack(lua)?;
770
771 let idx = idx.try_into().unwrap();
772 if lua.unlikely_memory_error() {
773 ffi::lua_rawseti(state, -2, idx);
774 } else {
775 protect_lua!(state, 2, 0, |state| ffi::lua_rawseti(state, -2, idx))?;
776 }
777 }
778 Ok(())
779 }
780
781 #[cfg(feature = "serialize")]
782 pub(crate) fn is_array(&self) -> bool {
783 let lua = self.0.lua;
784 let state = lua.state();
785 unsafe {
786 let _sg = StackGuard::new(state);
787 assert_stack(state, 3);
788
789 lua.push_ref(&self.0);
790 if ffi::lua_getmetatable(state, -1) == 0 {
791 return false;
792 }
793 crate::serde::push_array_metatable(state);
794 ffi::lua_rawequal(state, -1, -2) != 0
795 }
796 }
797
798 #[cfg(feature = "luau")]
799 #[inline(always)]
800 pub(crate) fn check_readonly_write(&self) -> Result<()> {
801 if self.is_readonly() {
802 return Err(Error::runtime("attempt to modify a readonly table"));
803 }
804 Ok(())
805 }
806
807 pub(crate) fn fmt_pretty(
808 &self,
809 fmt: &mut fmt::Formatter,
810 ident: usize,
811 visited: &mut HashSet<*const c_void>,
812 ) -> fmt::Result {
813 visited.insert(self.to_pointer());
814
815 let t = self.clone();
816 let mut pairs = t.pairs::<Value, Value>().flatten().collect::<Vec<_>>();
818 pairs.sort_by(|(a, _), (b, _)| a.cmp(b));
820 if pairs.is_empty() {
821 return write!(fmt, "{{}}");
822 }
823 writeln!(fmt, "{{")?;
824 for (key, value) in pairs {
825 write!(fmt, "{}[", " ".repeat(ident + 2))?;
826 key.fmt_pretty(fmt, false, ident + 2, visited)?;
827 write!(fmt, "] = ")?;
828 value.fmt_pretty(fmt, true, ident + 2, visited)?;
829 writeln!(fmt, ",")?;
830 }
831 write!(fmt, "{}}}", " ".repeat(ident))
832 }
833}
834
835impl fmt::Debug for Table<'_> {
836 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
837 if fmt.alternate() {
838 return self.fmt_pretty(fmt, 0, &mut HashSet::new());
839 }
840 fmt.write_fmt(format_args!("Table({:?})", self.0))
841 }
842}
843
844impl<'lua> PartialEq for Table<'lua> {
845 fn eq(&self, other: &Self) -> bool {
846 self.0 == other.0
847 }
848}
849
850impl<'lua> AsRef<Table<'lua>> for Table<'lua> {
851 #[inline]
852 fn as_ref(&self) -> &Self {
853 self
854 }
855}
856
857impl<'lua, T> PartialEq<[T]> for Table<'lua>
858where
859 T: IntoLua<'lua> + Clone,
860{
861 fn eq(&self, other: &[T]) -> bool {
862 let lua = self.0.lua;
863 let state = lua.state();
864 unsafe {
865 let _sg = StackGuard::new(state);
866 assert_stack(state, 4);
867
868 lua.push_ref(&self.0);
869
870 let len = ffi::lua_rawlen(state, -1);
871 for i in 0..len {
872 ffi::lua_rawgeti(state, -1, (i + 1) as _);
873 let val = lua.pop_value();
874 if val == Nil {
875 return i == other.len();
876 }
877 match other.get(i).map(|v| v.clone().into_lua(lua)) {
878 Some(Ok(other_val)) if val == other_val => continue,
879 _ => return false,
880 }
881 }
882 }
883 true
884 }
885}
886
887impl<'lua, T> PartialEq<&[T]> for Table<'lua>
888where
889 T: IntoLua<'lua> + Clone,
890{
891 #[inline]
892 fn eq(&self, other: &&[T]) -> bool {
893 self == *other
894 }
895}
896
897impl<'lua, T, const N: usize> PartialEq<[T; N]> for Table<'lua>
898where
899 T: IntoLua<'lua> + Clone,
900{
901 #[inline]
902 fn eq(&self, other: &[T; N]) -> bool {
903 self == &other[..]
904 }
905}
906
907pub trait TableExt<'lua>: Sealed {
909 fn call<A, R>(&self, args: A) -> Result<R>
913 where
914 A: IntoLuaMulti<'lua>,
915 R: FromLuaMulti<'lua>;
916
917 #[cfg(feature = "async")]
921 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
922 fn call_async<A, R>(&self, args: A) -> LocalBoxFuture<'lua, Result<R>>
923 where
924 A: IntoLuaMulti<'lua>,
925 R: FromLuaMulti<'lua> + 'lua;
926
927 fn call_method<A, R>(&self, name: &str, args: A) -> Result<R>
935 where
936 A: IntoLuaMulti<'lua>,
937 R: FromLuaMulti<'lua>;
938
939 fn call_function<A, R>(&self, name: &str, args: A) -> Result<R>
947 where
948 A: IntoLuaMulti<'lua>,
949 R: FromLuaMulti<'lua>;
950
951 #[cfg(feature = "async")]
958 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
959 fn call_async_method<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'lua, Result<R>>
960 where
961 A: IntoLuaMulti<'lua>,
962 R: FromLuaMulti<'lua> + 'lua;
963
964 #[cfg(feature = "async")]
971 #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
972 fn call_async_function<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'lua, Result<R>>
973 where
974 A: IntoLuaMulti<'lua>,
975 R: FromLuaMulti<'lua> + 'lua;
976}
977
978impl<'lua> TableExt<'lua> for Table<'lua> {
979 fn call<A, R>(&self, args: A) -> Result<R>
980 where
981 A: IntoLuaMulti<'lua>,
982 R: FromLuaMulti<'lua>,
983 {
984 Function(self.0.clone()).call(args)
986 }
987
988 #[cfg(feature = "async")]
989 fn call_async<A, R>(&self, args: A) -> LocalBoxFuture<'lua, Result<R>>
990 where
991 A: IntoLuaMulti<'lua>,
992 R: FromLuaMulti<'lua> + 'lua,
993 {
994 let args = match args.into_lua_multi(self.0.lua) {
995 Ok(args) => args,
996 Err(e) => return Box::pin(future::err(e)),
997 };
998 let func = Function(self.0.clone());
999 Box::pin(async move { func.call_async(args).await })
1000 }
1001
1002 fn call_method<A, R>(&self, name: &str, args: A) -> Result<R>
1003 where
1004 A: IntoLuaMulti<'lua>,
1005 R: FromLuaMulti<'lua>,
1006 {
1007 let lua = self.0.lua;
1008 let mut args = args.into_lua_multi(lua)?;
1009 args.push_front(Value::Table(self.clone()));
1010 self.get::<_, Function>(name)?.call(args)
1011 }
1012
1013 fn call_function<A, R>(&self, name: &str, args: A) -> Result<R>
1014 where
1015 A: IntoLuaMulti<'lua>,
1016 R: FromLuaMulti<'lua>,
1017 {
1018 self.get::<_, Function>(name)?.call(args)
1019 }
1020
1021 #[cfg(feature = "async")]
1022 fn call_async_method<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'lua, Result<R>>
1023 where
1024 A: IntoLuaMulti<'lua>,
1025 R: FromLuaMulti<'lua> + 'lua,
1026 {
1027 let lua = self.0.lua;
1028 let mut args = match args.into_lua_multi(lua) {
1029 Ok(args) => args,
1030 Err(e) => return Box::pin(future::err(e)),
1031 };
1032 args.push_front(Value::Table(self.clone()));
1033 self.call_async_function(name, args)
1034 }
1035
1036 #[cfg(feature = "async")]
1037 fn call_async_function<A, R>(&self, name: &str, args: A) -> LocalBoxFuture<'lua, Result<R>>
1038 where
1039 A: IntoLuaMulti<'lua>,
1040 R: FromLuaMulti<'lua> + 'lua,
1041 {
1042 let lua = self.0.lua;
1043 let args = match args.into_lua_multi(lua) {
1044 Ok(args) => args,
1045 Err(e) => return Box::pin(future::err(e)),
1046 };
1047 match self.get::<_, Function>(name) {
1048 Ok(func) => Box::pin(async move { func.call_async(args).await }),
1049 Err(e) => Box::pin(future::err(e)),
1050 }
1051 }
1052}
1053
1054#[cfg(feature = "serialize")]
1056pub(crate) struct SerializableTable<'a, 'lua> {
1057 table: &'a Table<'lua>,
1058 options: crate::serde::de::Options,
1059 visited: Rc<RefCell<FxHashSet<*const c_void>>>,
1060}
1061
1062#[cfg(feature = "serialize")]
1063impl<'lua> Serialize for Table<'lua> {
1064 #[inline]
1065 fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
1066 SerializableTable::new(self, Default::default(), Default::default()).serialize(serializer)
1067 }
1068}
1069
1070#[cfg(feature = "serialize")]
1071impl<'a, 'lua> SerializableTable<'a, 'lua> {
1072 #[inline]
1073 pub(crate) fn new(
1074 table: &'a Table<'lua>,
1075 options: crate::serde::de::Options,
1076 visited: Rc<RefCell<FxHashSet<*const c_void>>>,
1077 ) -> Self {
1078 Self {
1079 table,
1080 options,
1081 visited,
1082 }
1083 }
1084}
1085
1086#[cfg(feature = "serialize")]
1087impl<'a, 'lua> Serialize for SerializableTable<'a, 'lua> {
1088 fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
1089 where
1090 S: Serializer,
1091 {
1092 use crate::serde::de::{check_value_for_skip, MapPairs, RecursionGuard};
1093 use crate::value::SerializableValue;
1094
1095 let convert_result = |res: Result<()>, serialize_err: Option<S::Error>| match res {
1096 Ok(v) => Ok(v),
1097 Err(Error::SerializeError(_)) if serialize_err.is_some() => Err(serialize_err.unwrap()),
1098 Err(Error::SerializeError(msg)) => Err(serde::ser::Error::custom(msg)),
1099 Err(err) => Err(serde::ser::Error::custom(err.to_string())),
1100 };
1101
1102 let options = self.options;
1103 let visited = &self.visited;
1104 let _guard = RecursionGuard::new(self.table, visited);
1105
1106 let len = self.table.raw_len();
1108 if len > 0 || self.table.is_array() {
1109 let mut seq = serializer.serialize_seq(Some(len))?;
1110 let mut serialize_err = None;
1111 let res = self.table.for_each_value::<Value>(|value| {
1112 let skip = check_value_for_skip(&value, self.options, visited)
1113 .map_err(|err| Error::SerializeError(err.to_string()))?;
1114 if skip {
1115 return Ok(());
1117 }
1118 seq.serialize_element(&SerializableValue::new(&value, options, Some(visited)))
1119 .map_err(|err| {
1120 serialize_err = Some(err);
1121 Error::SerializeError(String::new())
1122 })
1123 });
1124 convert_result(res, serialize_err)?;
1125 return seq.end();
1126 }
1127
1128 let mut map = serializer.serialize_map(None)?;
1130 let mut serialize_err = None;
1131 let mut process_pair = |key, value| {
1132 let skip_key = check_value_for_skip(&key, self.options, visited)
1133 .map_err(|err| Error::SerializeError(err.to_string()))?;
1134 let skip_value = check_value_for_skip(&value, self.options, visited)
1135 .map_err(|err| Error::SerializeError(err.to_string()))?;
1136 if skip_key || skip_value {
1137 return Ok(());
1139 }
1140 map.serialize_entry(
1141 &SerializableValue::new(&key, options, Some(visited)),
1142 &SerializableValue::new(&value, options, Some(visited)),
1143 )
1144 .map_err(|err| {
1145 serialize_err = Some(err);
1146 Error::SerializeError(String::new())
1147 })
1148 };
1149
1150 let res = if !self.options.sort_keys {
1151 self.table.for_each(process_pair)
1153 } else {
1154 MapPairs::new(self.table.clone(), self.options.sort_keys)
1155 .map_err(serde::ser::Error::custom)?
1156 .try_for_each(|kv| {
1157 let (key, value) = kv?;
1158 process_pair(key, value)
1159 })
1160 };
1161 convert_result(res, serialize_err)?;
1162 map.end()
1163 }
1164}
1165
1166pub struct TablePairs<'lua, K, V> {
1172 table: LuaRef<'lua>,
1173 key: Option<Value<'lua>>,
1174 _phantom: PhantomData<(K, V)>,
1175}
1176
1177impl<'lua, K, V> Iterator for TablePairs<'lua, K, V>
1178where
1179 K: FromLua<'lua>,
1180 V: FromLua<'lua>,
1181{
1182 type Item = Result<(K, V)>;
1183
1184 fn next(&mut self) -> Option<Self::Item> {
1185 if let Some(prev_key) = self.key.take() {
1186 let lua = self.table.lua;
1187 let state = lua.state();
1188
1189 let res = (|| unsafe {
1190 let _sg = StackGuard::new(state);
1191 check_stack(state, 5)?;
1192
1193 lua.push_ref(&self.table);
1194 lua.push_value(prev_key)?;
1195
1196 if ffi::lua_next(state, -2) != 0 {
1200 let key = lua.stack_value(-2);
1201 Ok(Some((
1202 key.clone(),
1203 K::from_lua(key, lua)?,
1204 V::from_stack(-1, lua)?,
1205 )))
1206 } else {
1207 Ok(None)
1208 }
1209 })();
1210
1211 match res {
1212 Ok(Some((key, ret_key, value))) => {
1213 self.key = Some(key);
1214 Some(Ok((ret_key, value)))
1215 }
1216 Ok(None) => None,
1217 Err(e) => Some(Err(e)),
1218 }
1219 } else {
1220 None
1221 }
1222 }
1223}
1224
1225pub struct TableSequence<'lua, V> {
1231 table: LuaRef<'lua>,
1233 index: Integer,
1234 _phantom: PhantomData<V>,
1235}
1236
1237impl<'lua, V> Iterator for TableSequence<'lua, V>
1238where
1239 V: FromLua<'lua>,
1240{
1241 type Item = Result<V>;
1242
1243 fn next(&mut self) -> Option<Self::Item> {
1244 let lua = self.table.lua;
1245 let state = lua.state();
1246 unsafe {
1247 let _sg = StackGuard::new(state);
1248 if let Err(err) = check_stack(state, 1) {
1249 return Some(Err(err));
1250 }
1251
1252 lua.push_ref(&self.table);
1253 match ffi::lua_rawgeti(state, -1, self.index) {
1254 ffi::LUA_TNIL => None,
1255 _ => {
1256 self.index += 1;
1257 Some(V::from_stack(-1, lua))
1258 }
1259 }
1260 }
1261 }
1262}
1263
1264#[cfg(test)]
1265mod assertions {
1266 use super::*;
1267
1268 static_assertions::assert_not_impl_any!(Table: Send);
1269
1270 #[cfg(feature = "unstable")]
1271 static_assertions::assert_not_impl_any!(OwnedTable: Send);
1272}