1use oxi_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
52impl<T: Into<Object>> FromIterator<T> for Array {
53 #[inline]
54 fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
55 Self(
56 iter.into_iter()
57 .map(Into::into)
58 .filter(|obj| obj.is_some())
59 .collect(),
60 )
61 }
62}
63
64impl IntoIterator for Array {
65 type Item = Object;
66 type IntoIter = ArrayIterator;
67
68 #[inline]
69 fn into_iter(self) -> Self::IntoIter {
70 ArrayIterator(self.0.into_iter())
71 }
72}
73
74#[derive(Clone)]
76pub struct ArrayIterator(kvec::IntoIter<Object>);
77
78impl Iterator for ArrayIterator {
79 type Item = Object;
80
81 #[inline]
82 fn next(&mut self) -> Option<Self::Item> {
83 self.0.next()
84 }
85
86 #[inline]
87 fn size_hint(&self) -> (usize, Option<usize>) {
88 self.0.size_hint()
89 }
90}
91
92impl ExactSizeIterator for ArrayIterator {
93 #[inline]
94 fn len(&self) -> usize {
95 self.0.len()
96 }
97}
98
99impl DoubleEndedIterator for ArrayIterator {
100 #[inline]
101 fn next_back(&mut self) -> Option<Self::Item> {
102 self.0.next_back()
103 }
104}
105
106impl core::iter::FusedIterator for ArrayIterator {}
107
108impl lua::Poppable for Array {
109 #[inline]
110 unsafe fn pop(
111 lstate: *mut lua::ffi::lua_State,
112 ) -> Result<Self, lua::Error> {
113 use lua::ffi::*;
114
115 if lua_gettop(lstate) == 0 {
116 return Err(lua::Error::PopEmptyStack);
117 } else if lua_type(lstate, -1) != LUA_TTABLE {
118 let ty = lua_type(lstate, -1);
119 return Err(lua::Error::pop_wrong_type::<Self>(LUA_TTABLE, ty));
120 }
121
122 let mut kvec = KVec::with_capacity(lua_objlen(lstate, -1));
126
127 lua_pushnil(lstate);
128
129 while lua_next(lstate, -2) != 0 {
130 kvec.push(Object::pop(lstate)?);
131 }
132
133 lua_pop(lstate, 1);
135
136 Ok(Self(kvec))
137 }
138}
139
140impl lua::Pushable for Array {
141 #[inline]
142 unsafe fn push(
143 self,
144 lstate: *mut lua::ffi::lua_State,
145 ) -> Result<core::ffi::c_int, lua::Error> {
146 use lua::ffi::*;
147
148 lua_createtable(lstate, self.len() as _, 0);
149
150 for (idx, obj) in self.into_iter().enumerate() {
151 obj.push(lstate)?;
152 lua_rawseti(lstate, -2, (idx + 1) as _);
153 }
154
155 Ok(1)
156 }
157}
158
159macro_rules! from_tuple {
162 ($($ty:ident)*) => {
163 impl <$($ty: Into<Object>),*> From<($($ty,)*)> for Array {
164 #[allow(non_snake_case)]
165 fn from(($($ty,)*): ($($ty,)*)) -> Self {
166 Self::from_iter([$($ty.into(),)*])
167 }
168 }
169 };
170}
171
172from_tuple!(A);
173from_tuple!(A B);
174from_tuple!(A B C);
175from_tuple!(A B C D);
176from_tuple!(A B C D E);
177from_tuple!(A B C D E F);
178from_tuple!(A B C D E F G);
179from_tuple!(A B C D E F G H);
180from_tuple!(A B C D E F G H I);
181from_tuple!(A B C D E F G H I J);
182from_tuple!(A B C D E F G H I J K);
183from_tuple!(A B C D E F G H I J K L);
184from_tuple!(A B C D E F G H I J K L M);
185from_tuple!(A B C D E F G H I J K L M N);
186from_tuple!(A B C D E F G H I J K L M N O);
187from_tuple!(A B C D E F G H I J K L M N O P);
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn array_layout() {
195 use core::alloc::Layout;
196
197 assert_eq!(Layout::new::<Array>(), Layout::new::<KVec<Object>>());
198 }
199
200 #[test]
201 fn iter_basic() {
202 let array = Array::from_iter(["Foo", "Bar", "Baz"]);
203
204 let mut iter = array.into_iter();
205 assert_eq!(Some(Object::from("Foo")), iter.next());
206 assert_eq!(Some(Object::from("Bar")), iter.next());
207 assert_eq!(Some(Object::from("Baz")), iter.next());
208 assert_eq!(None, iter.next());
209 }
210
211 #[test]
212 fn drop_iter_halfway() {
213 let array = Array::from_iter(["Foo", "Bar", "Baz"]);
214
215 let mut iter = array.into_iter();
216 assert_eq!(Some(Object::from("Foo")), iter.next());
217 }
218
219 #[test]
220 fn empty_array() {
221 let empty = Array::default();
222 assert_eq!(0, empty.into_iter().count());
223 }
224}