nvim_types/
array.rs

1use std::ffi::c_int;
2use std::fmt::{self, Debug, Display};
3use std::mem::ManuallyDrop;
4use std::ptr;
5
6use luajit_bindings::{self as lua, ffi::lua_State};
7
8use super::{KVec, Object};
9
10// https://github.com/neovim/neovim/blob/master/src/nvim/api/private/defs.h#L94
11//
12/// A vector of Neovim [`Object`](Object)s.
13pub type Array = KVec<Object>;
14
15impl Debug for Array {
16    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
17        f.debug_list().entries(self.iter()).finish()
18    }
19}
20
21impl Display for Array {
22    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23        Debug::fmt(self, f)
24    }
25}
26
27impl lua::Pushable for Array {
28    unsafe fn push(self, state: *mut lua_State) -> Result<c_int, lua::Error> {
29        <Vec<Object>>::from(self).push(state)
30    }
31}
32
33impl lua::Poppable for Array {
34    unsafe fn pop(state: *mut lua_State) -> Result<Self, lua::Error> {
35        <Vec<Object> as lua::Poppable>::pop(state).map(Into::into)
36    }
37}
38
39impl IntoIterator for Array {
40    type IntoIter = ArrayIterator;
41    type Item = <ArrayIterator as Iterator>::Item;
42
43    #[inline]
44    fn into_iter(self) -> Self::IntoIter {
45        // Wrap `self` in `ManuallyDrop` to avoid running destructor.
46        let arr = ManuallyDrop::new(self);
47        let start = arr.items;
48        let end = unsafe { start.add(arr.len()) };
49        ArrayIterator { start, end }
50    }
51}
52
53impl<T> FromIterator<T> for Array
54where
55    T: Into<Object>,
56{
57    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
58        iter.into_iter()
59            .map(Into::into)
60            .filter(Object::is_some) // TODO: maybe  avoid this
61            .collect::<Vec<Object>>()
62            .into()
63    }
64}
65
66/// An owning iterator over the [`Object`]s of a Neovim [`Array`].
67pub struct ArrayIterator {
68    start: *const Object,
69    end: *const Object,
70}
71
72impl Iterator for ArrayIterator {
73    type Item = Object;
74
75    #[inline]
76    fn next(&mut self) -> Option<Self::Item> {
77        if self.start == self.end {
78            return None;
79        }
80        let current = self.start;
81        self.start = unsafe { self.start.offset(1) };
82        Some(unsafe { ptr::read(current) })
83    }
84
85    #[inline]
86    fn size_hint(&self) -> (usize, Option<usize>) {
87        let exact = self.len();
88        (exact, Some(exact))
89    }
90
91    #[inline]
92    fn count(self) -> usize {
93        self.len()
94    }
95}
96
97impl ExactSizeIterator for ArrayIterator {
98    fn len(&self) -> usize {
99        unsafe { self.end.offset_from(self.start) as usize }
100    }
101}
102
103impl DoubleEndedIterator for ArrayIterator {
104    #[inline]
105    fn next_back(&mut self) -> Option<Self::Item> {
106        if self.start == self.end {
107            return None;
108        }
109        let current = self.end;
110        self.end = unsafe { self.end.offset(-1) };
111        Some(unsafe { ptr::read(current) })
112    }
113}
114
115impl std::iter::FusedIterator for ArrayIterator {}
116
117impl Drop for ArrayIterator {
118    fn drop(&mut self) {
119        while self.start != self.end {
120            unsafe {
121                ptr::drop_in_place(self.start as *mut Object);
122                self.start = self.start.offset(1);
123            }
124        }
125    }
126}
127
128/// Implements `From<(A, B, C, ..)> for Array` for tuples `(A, B, C, ..)` where
129/// all the elements in the tuple implement `Into<Object>`.
130macro_rules! from_tuple {
131    ($($ty:ident)*) => {
132        impl <$($ty: Into<Object>),*> From<($($ty,)*)> for Array {
133            #[allow(non_snake_case)]
134            fn from(($($ty,)*): ($($ty,)*)) -> Self {
135                Self::from_iter([$($ty.into(),)*])
136            }
137        }
138    };
139}
140
141from_tuple!(A);
142from_tuple!(A B);
143from_tuple!(A B C);
144from_tuple!(A B C D);
145from_tuple!(A B C D E);
146from_tuple!(A B C D E F);
147from_tuple!(A B C D E F G);
148from_tuple!(A B C D E F G H);
149from_tuple!(A B C D E F G H I);
150from_tuple!(A B C D E F G H I J);
151from_tuple!(A B C D E F G H I J K);
152from_tuple!(A B C D E F G H I J K L);
153from_tuple!(A B C D E F G H I J K L M);
154from_tuple!(A B C D E F G H I J K L M N);
155from_tuple!(A B C D E F G H I J K L M N O);
156from_tuple!(A B C D E F G H I J K L M N O P);
157
158#[cfg(test)]
159mod tests {
160    use super::*;
161
162    #[test]
163    fn iter_basic() {
164        let array = Array::from_iter(["Foo", "Bar", "Baz"]);
165
166        let mut iter = array.into_iter();
167        assert_eq!(Some(Object::from("Foo")), iter.next());
168        assert_eq!(Some(Object::from("Bar")), iter.next());
169        assert_eq!(Some(Object::from("Baz")), iter.next());
170        assert_eq!(None, iter.next());
171    }
172
173    #[test]
174    fn drop_iter_halfway() {
175        let array = Array::from_iter(["Foo", "Bar", "Baz"]);
176
177        let mut iter = array.into_iter();
178        assert_eq!(Some(Object::from("Foo")), iter.next());
179    }
180
181    #[test]
182    fn empty_array() {
183        let empty = Array { size: 0, capacity: 0, items: ptr::null_mut() };
184        assert_eq!(0, empty.into_iter().count());
185    }
186
187    #[test]
188    fn debug_array() {
189        let arr = Array::from((1, 2, 3, "a", true));
190        assert_eq!(String::from("[1, 2, 3, \"a\", true]"), format!("{arr}"));
191    }
192
193    #[test]
194    fn debug_nested_array() {
195        let arr = Array::from_iter([Array::from((1, 2, 3))]);
196        assert_eq!(String::from("[[1, 2, 3]]"), format!("{arr}"));
197    }
198}