1use core::ops::{Deref, DerefMut};
2
3use luajit as lua;
4
5use crate::NonOwning;
6use crate::Object;
7use crate::kvec::{self, KVec};
8
9#[derive(Clone, Default, PartialEq)]
11#[repr(transparent)]
12pub struct Array(pub(super) KVec<Object>);
13
14#[derive(Clone)]
16pub struct ArrayIterator(kvec::IntoIter<Object>);
17
18#[derive(Debug, PartialEq, Eq, thiserror::Error)]
20pub enum ArrayFromTupleError<T> {
21 #[error(
23 "not enough elements in the array, expected {expected_len} but got \
24 {actual_len}"
25 )]
26 NotEnoughElements { expected_len: usize, actual_len: usize },
27 #[error(
30 "couldn't convert tuple element at index {element_idx} into object: \
31 {error:?}"
32 )]
33 ElementFromObject { element_idx: usize, error: T },
34}
35
36impl core::fmt::Debug for Array {
37 #[inline]
38 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
39 f.debug_list().entries(self.iter()).finish()
40 }
41}
42
43impl Array {
44 #[inline]
46 pub fn len(&self) -> usize {
47 self.0.len()
48 }
49
50 #[inline]
52 pub fn is_empty(&self) -> bool {
53 self.0.is_empty()
54 }
55
56 #[inline]
58 pub fn iter(&self) -> core::slice::Iter<'_, Object> {
59 self.0.as_slice().iter()
60 }
61
62 #[inline]
64 pub fn new() -> Self {
65 Self(KVec::new())
66 }
67
68 #[inline]
70 pub fn non_owning(&self) -> NonOwning<'_, Self> {
71 #[allow(clippy::unnecessary_struct_initialization)]
72 NonOwning::new(Self(KVec { ..self.0 }))
73 }
74
75 #[inline]
77 pub fn push<V>(&mut self, value: V)
78 where
79 V: Into<Object>,
80 {
81 let value = value.into();
82 if !value.is_nil() {
83 self.0.push(value);
84 }
85 }
86
87 #[track_caller]
95 #[inline]
96 pub fn swap_remove(&mut self, index: usize) -> Object {
97 self.0.swap_remove(index)
98 }
99}
100
101impl Deref for Array {
102 type Target = [Object];
103
104 #[inline]
105 fn deref(&self) -> &Self::Target {
106 self.0.as_slice()
107 }
108}
109
110impl DerefMut for Array {
111 #[inline]
112 fn deref_mut(&mut self) -> &mut Self::Target {
113 self.0.as_mut_slice()
114 }
115}
116
117impl<T: Into<Object>> Extend<T> for Array {
118 #[inline]
119 fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
120 for value in iter {
121 self.push(value);
122 }
123 }
124}
125
126impl<T: Into<Object>> FromIterator<T> for Array {
127 #[inline]
128 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
129 let mut array = Self::new();
130 array.extend(iter);
131 array
132 }
133}
134
135impl IntoIterator for Array {
136 type Item = Object;
137 type IntoIter = ArrayIterator;
138
139 #[inline]
140 fn into_iter(self) -> Self::IntoIter {
141 ArrayIterator(self.0.into_iter())
142 }
143}
144
145impl Iterator for ArrayIterator {
146 type Item = Object;
147
148 #[inline]
149 fn next(&mut self) -> Option<Self::Item> {
150 self.0.next()
151 }
152
153 #[inline]
154 fn size_hint(&self) -> (usize, Option<usize>) {
155 self.0.size_hint()
156 }
157}
158
159impl ExactSizeIterator for ArrayIterator {
160 #[inline]
161 fn len(&self) -> usize {
162 self.0.len()
163 }
164}
165
166impl DoubleEndedIterator for ArrayIterator {
167 #[inline]
168 fn next_back(&mut self) -> Option<Self::Item> {
169 self.0.next_back()
170 }
171}
172
173impl core::iter::FusedIterator for ArrayIterator {}
174
175impl lua::Poppable for Array {
176 #[inline]
177 unsafe fn pop(lstate: *mut lua::ffi::State) -> Result<Self, lua::Error> {
178 use lua::ffi::*;
179
180 if lua_gettop(lstate) == 0 {
181 return Err(lua::Error::PopEmptyStack);
182 } else if lua_type(lstate, -1) != LUA_TTABLE {
183 let ty = lua_type(lstate, -1);
184 return Err(lua::Error::pop_wrong_type::<Self>(LUA_TTABLE, ty));
185 }
186
187 let mut kvec = KVec::with_capacity(lua_objlen(lstate, -1));
191
192 lua_pushnil(lstate);
193
194 while lua_next(lstate, -2) != 0 {
195 kvec.push(Object::pop(lstate)?);
196 }
197
198 lua_pop(lstate, 1);
200
201 Ok(Self(kvec))
202 }
203}
204
205impl lua::Pushable for Array {
206 #[inline]
207 unsafe fn push(
208 self,
209 lstate: *mut lua::ffi::State,
210 ) -> Result<core::ffi::c_int, lua::Error> {
211 use lua::ffi::*;
212
213 lua_createtable(lstate, self.len() as _, 0);
214
215 for (idx, obj) in
216 self.into_iter().filter(|obj| !obj.is_nil()).enumerate()
217 {
218 obj.push(lstate)?;
219 lua_rawseti(lstate, -2, (idx + 1) as _);
220 }
221
222 Ok(1)
223 }
224}
225
226macro_rules! array_from_tuple {
229 ($($ty:ident)*) => {
230 impl <$($ty: Into<Object>),*> From<($($ty,)*)> for Array {
231 #[allow(non_snake_case)]
232 fn from(($($ty,)*): ($($ty,)*)) -> Self {
233 Self::from_iter([$($ty.into(),)*])
234 }
235 }
236 };
237}
238
239array_from_tuple!(A);
240array_from_tuple!(A B);
241array_from_tuple!(A B C);
242array_from_tuple!(A B C D);
243array_from_tuple!(A B C D E);
244array_from_tuple!(A B C D E F);
245array_from_tuple!(A B C D E F G);
246array_from_tuple!(A B C D E F G H);
247array_from_tuple!(A B C D E F G H I);
248array_from_tuple!(A B C D E F G H I J);
249array_from_tuple!(A B C D E F G H I J K);
250array_from_tuple!(A B C D E F G H I J K L);
251array_from_tuple!(A B C D E F G H I J K L M);
252array_from_tuple!(A B C D E F G H I J K L M N);
253array_from_tuple!(A B C D E F G H I J K L M N O);
254array_from_tuple!(A B C D E F G H I J K L M N O P);
255
256macro_rules! count {
257 () => {0i32};
258 ($x:tt $($xs:tt)*) => {1i32 + count!($($xs)*)};
259}
260
261macro_rules! tuple_try_from_array {
264 ($($ty:ident)*) => {
265 impl<Error, $($ty,)*> TryFrom<Array> for ($($ty,)*)
266 where
267 $($ty: TryFrom<Object, Error = Error>,)*
268 {
269 type Error = ArrayFromTupleError<Error>;
270
271 #[inline]
272 #[allow(non_snake_case)]
273 fn try_from(array: Array) -> Result<Self, Self::Error> {
274 let actual_len = array.len();
275 let expected_len = count!($($ty)*) as usize;
276
277 if actual_len < expected_len {
278 return Err(ArrayFromTupleError::NotEnoughElements {
279 expected_len,
280 actual_len
281 });
282 }
283
284 let mut iter = array.into_iter();
285
286 $(
287 let $ty = $ty::try_from(
288 iter.next().expect("already checked len")
289 ).map_err(|error| ArrayFromTupleError::ElementFromObject {
290 element_idx: actual_len - iter.len() - 1,
291 error
292 })?;
293 )*
294
295 Ok(($($ty,)*))
296 }
297 }
298 };
299}
300
301tuple_try_from_array!(A);
302tuple_try_from_array!(A B);
303tuple_try_from_array!(A B C);
304tuple_try_from_array!(A B C D);
305tuple_try_from_array!(A B C D E);
306tuple_try_from_array!(A B C D E F);
307tuple_try_from_array!(A B C D E F G);
308tuple_try_from_array!(A B C D E F G H);
309tuple_try_from_array!(A B C D E F G H I);
310tuple_try_from_array!(A B C D E F G H I J);
311tuple_try_from_array!(A B C D E F G H I J K);
312tuple_try_from_array!(A B C D E F G H I J K L);
313tuple_try_from_array!(A B C D E F G H I J K L M);
314tuple_try_from_array!(A B C D E F G H I J K L M N);
315tuple_try_from_array!(A B C D E F G H I J K L M N O);
316tuple_try_from_array!(A B C D E F G H I J K L M N O P);
317
318#[cfg(test)]
319mod tests {
320 use super::*;
321
322 #[test]
323 fn array_layout() {
324 use core::alloc::Layout;
325
326 assert_eq!(Layout::new::<Array>(), Layout::new::<KVec<Object>>());
327 }
328
329 #[test]
330 fn iter_basic() {
331 let array = Array::from_iter(["Foo", "Bar", "Baz"]);
332
333 let mut iter = array.into_iter();
334 assert_eq!(Some(Object::from("Foo")), iter.next());
335 assert_eq!(Some(Object::from("Bar")), iter.next());
336 assert_eq!(Some(Object::from("Baz")), iter.next());
337 assert_eq!(None, iter.next());
338 }
339
340 #[test]
341 fn drop_iter_halfway() {
342 let array = Array::from_iter(["Foo", "Bar", "Baz"]);
343
344 let mut iter = array.into_iter();
345 assert_eq!(Some(Object::from("Foo")), iter.next());
346 }
347
348 #[test]
349 fn empty_array() {
350 let empty = Array::default();
351 assert_eq!(0, empty.into_iter().count());
352 }
353}