1use luajit as lua;
2
3use crate::kvec::{self, KVec};
4use crate::NonOwning;
5use crate::Object;
6
7#[derive(Clone, Default, PartialEq)]
9#[repr(transparent)]
10pub struct Array(pub(super) KVec<Object>);
11
12impl core::fmt::Debug for Array {
13 #[inline]
14 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
15 f.debug_list().entries(self.iter()).finish()
16 }
17}
18
19impl Array {
20 #[inline]
22 pub fn len(&self) -> usize {
23 self.0.len()
24 }
25
26 #[inline]
28 pub fn is_empty(&self) -> bool {
29 self.0.is_empty()
30 }
31
32 #[inline]
34 pub fn iter(&self) -> core::slice::Iter<'_, Object> {
35 self.0.as_slice().iter()
36 }
37
38 #[inline]
40 pub fn new() -> Self {
41 Self(KVec::new())
42 }
43
44 #[inline]
46 pub fn non_owning(&self) -> NonOwning<'_, Self> {
47 #[allow(clippy::unnecessary_struct_initialization)]
48 NonOwning::new(Self(KVec { ..self.0 }))
49 }
50
51 #[inline]
53 pub fn push<V>(&mut self, value: V)
54 where
55 V: Into<Object>,
56 {
57 self.0.push(value.into());
58 }
59}
60
61impl<T: Into<Object>> FromIterator<T> for Array {
62 #[inline]
63 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
64 Self(
65 iter.into_iter()
66 .map(Into::into)
67 .filter(|obj| obj.is_some())
68 .collect(),
69 )
70 }
71}
72
73impl IntoIterator for Array {
74 type Item = Object;
75 type IntoIter = ArrayIterator;
76
77 #[inline]
78 fn into_iter(self) -> Self::IntoIter {
79 ArrayIterator(self.0.into_iter())
80 }
81}
82
83#[derive(Clone)]
85pub struct ArrayIterator(kvec::IntoIter<Object>);
86
87impl Iterator for ArrayIterator {
88 type Item = Object;
89
90 #[inline]
91 fn next(&mut self) -> Option<Self::Item> {
92 self.0.next()
93 }
94
95 #[inline]
96 fn size_hint(&self) -> (usize, Option<usize>) {
97 self.0.size_hint()
98 }
99}
100
101impl ExactSizeIterator for ArrayIterator {
102 #[inline]
103 fn len(&self) -> usize {
104 self.0.len()
105 }
106}
107
108impl DoubleEndedIterator for ArrayIterator {
109 #[inline]
110 fn next_back(&mut self) -> Option<Self::Item> {
111 self.0.next_back()
112 }
113}
114
115impl core::iter::FusedIterator for ArrayIterator {}
116
117impl lua::Poppable for Array {
118 #[inline]
119 unsafe fn pop(
120 lstate: *mut lua::ffi::lua_State,
121 ) -> Result<Self, lua::Error> {
122 use lua::ffi::*;
123
124 if lua_gettop(lstate) == 0 {
125 return Err(lua::Error::PopEmptyStack);
126 } else if lua_type(lstate, -1) != LUA_TTABLE {
127 let ty = lua_type(lstate, -1);
128 return Err(lua::Error::pop_wrong_type::<Self>(LUA_TTABLE, ty));
129 }
130
131 let mut kvec = KVec::with_capacity(lua_objlen(lstate, -1));
135
136 lua_pushnil(lstate);
137
138 while lua_next(lstate, -2) != 0 {
139 kvec.push(Object::pop(lstate)?);
140 }
141
142 lua_pop(lstate, 1);
144
145 Ok(Self(kvec))
146 }
147}
148
149impl lua::Pushable for Array {
150 #[inline]
151 unsafe fn push(
152 self,
153 lstate: *mut lua::ffi::lua_State,
154 ) -> Result<core::ffi::c_int, lua::Error> {
155 use lua::ffi::*;
156
157 lua_createtable(lstate, self.len() as _, 0);
158
159 for (idx, obj) in self.into_iter().enumerate() {
160 obj.push(lstate)?;
161 lua_rawseti(lstate, -2, (idx + 1) as _);
162 }
163
164 Ok(1)
165 }
166}
167
168macro_rules! from_tuple {
171 ($($ty:ident)*) => {
172 impl <$($ty: Into<Object>),*> From<($($ty,)*)> for Array {
173 #[allow(non_snake_case)]
174 fn from(($($ty,)*): ($($ty,)*)) -> Self {
175 Self::from_iter([$($ty.into(),)*])
176 }
177 }
178 };
179}
180
181from_tuple!(A);
182from_tuple!(A B);
183from_tuple!(A B C);
184from_tuple!(A B C D);
185from_tuple!(A B C D E);
186from_tuple!(A B C D E F);
187from_tuple!(A B C D E F G);
188from_tuple!(A B C D E F G H);
189from_tuple!(A B C D E F G H I);
190from_tuple!(A B C D E F G H I J);
191from_tuple!(A B C D E F G H I J K);
192from_tuple!(A B C D E F G H I J K L);
193from_tuple!(A B C D E F G H I J K L M);
194from_tuple!(A B C D E F G H I J K L M N);
195from_tuple!(A B C D E F G H I J K L M N O);
196from_tuple!(A B C D E F G H I J K L M N O P);
197
198#[cfg(test)]
199mod tests {
200 use super::*;
201
202 #[test]
203 fn array_layout() {
204 use core::alloc::Layout;
205
206 assert_eq!(Layout::new::<Array>(), Layout::new::<KVec<Object>>());
207 }
208
209 #[test]
210 fn iter_basic() {
211 let array = Array::from_iter(["Foo", "Bar", "Baz"]);
212
213 let mut iter = array.into_iter();
214 assert_eq!(Some(Object::from("Foo")), iter.next());
215 assert_eq!(Some(Object::from("Bar")), iter.next());
216 assert_eq!(Some(Object::from("Baz")), iter.next());
217 assert_eq!(None, iter.next());
218 }
219
220 #[test]
221 fn drop_iter_halfway() {
222 let array = Array::from_iter(["Foo", "Bar", "Baz"]);
223
224 let mut iter = array.into_iter();
225 assert_eq!(Some(Object::from("Foo")), iter.next());
226 }
227
228 #[test]
229 fn empty_array() {
230 let empty = Array::default();
231 assert_eq!(0, empty.into_iter().count());
232 }
233}