Skip to main content

aorist_extendr_api/wrapper/
list.rs

1use super::*;
2
3#[derive(Debug, PartialEq, Clone)]
4pub struct List {
5    pub(crate) robj: Robj,
6}
7
8impl Default for List {
9    fn default() -> Self {
10        List::new()
11    }
12}
13
14impl List {
15    /// Create a new, empty list.
16    /// ```
17    /// use extendr_api::prelude::*;
18    /// test! {
19    ///     let list = List::new();
20    ///     assert_eq!(list.is_list(), true);
21    ///     assert_eq!(list.len(), 0);
22    /// }
23    /// ```
24    pub fn new() -> List {
25        let values: &[Robj] = &[];
26        List::from_values(values)
27    }
28
29    /// Wrapper for creating list (VECSXP) objects.
30    /// ```
31    /// use extendr_api::prelude::*;
32    /// test! {
33    ///     let list = r!(List::from_values(&[r!(0), r!(1), r!(2)]));
34    ///     assert_eq!(list.is_list(), true);
35    ///     assert_eq!(list.len(), 3);
36    /// }
37    /// ```
38    pub fn from_values<V>(values: V) -> Self
39    where
40        V: IntoIterator,
41        V::IntoIter: ExactSizeIterator,
42        V::Item: Into<Robj>,
43    {
44        Self {
45            robj: make_vector(VECSXP, values),
46        }
47    }
48
49    pub fn from_pairs<V>(pairs: V) -> Self
50    where
51        V: IntoIterator,
52        V::IntoIter: ExactSizeIterator + Clone,
53        V::Item: Into<(&'static str, Robj)>,
54    {
55        let iter = pairs.into_iter();
56        let res = List::from_values(iter.clone().map(|kv| {
57            let (_, v) = kv.into();
58            v
59        }));
60        res.set_names(iter.map(|kv| {
61            let (k, _) = kv.into();
62            k
63        }))
64        .unwrap()
65        .as_list()
66        .unwrap()
67    }
68
69    /// Return an iterator over the values of this list.
70    /// ```
71    /// use extendr_api::prelude::*;
72    /// test! {
73    ///     let mut robj = list!(1, 2, 3);
74    ///     let objects : Vec<_> = robj.as_list().unwrap().values().collect();
75    ///     assert_eq!(objects, vec![r!(1), r!(2), r!(3)]);
76    /// }
77    /// ```
78    pub fn values(&self) -> ListIter {
79        ListIter::from_parts(self.robj.clone(), 0, self.robj.len())
80    }
81
82    /// Return an iterator over the names and values of this list.
83    /// ```
84    /// use extendr_api::prelude::*;
85    /// test! {
86    ///     let mut robj = list!(a=1, 2);
87    ///     let names_and_values : Vec<_> = robj.as_list().unwrap().iter().collect();
88    ///     assert_eq!(names_and_values, vec![("a", r!(1)), ("", r!(2))]);
89    /// }
90    /// ```
91    pub fn iter(&self) -> NamedListIter {
92        self.names()
93            .map(|n| n.zip(self.values()))
94            .unwrap_or_else(|| StrIter::new().zip(ListIter::new()))
95    }
96}
97
98impl IntoIterator for List {
99    type IntoIter = NamedListIter;
100    type Item = (&'static str, Robj);
101
102    /// Convert a List into an interator, consuming the list.
103    /// ```
104    /// use extendr_api::prelude::*;
105    /// test! {
106    ///     let list = list!(a=1, 2).as_list().unwrap();
107    ///     let vec : Vec<_> = list.into_iter().collect();
108    ///     assert_eq!(vec, vec![("a", r!(1)), ("", r!(2))]);
109    /// }
110    /// ```
111    fn into_iter(self) -> Self::IntoIter {
112        self.iter()
113    }
114}
115
116/// Iterator over the objects in a VECSXP, EXPRSXP or WEAKREFSXP.
117///
118/// ```
119/// use extendr_api::prelude::*;
120/// test! {
121///     let my_list = list!(a = 1, b = 2);
122///     let mut total = 0;
123///     for robj in my_list.as_list().unwrap().values() {
124///       if let Some(val) = robj.as_integer() {
125///         total += val;
126///       }
127///     }
128///     assert_eq!(total, 3);
129///    
130///     for name in my_list.names().unwrap() {
131///        assert!(name == "a" || name == "b")
132///     }
133/// }
134/// ```
135#[derive(Clone)]
136pub struct ListIter {
137    robj: Robj,
138    i: usize,
139    len: usize,
140}
141
142impl Default for ListIter {
143    fn default() -> Self {
144        ListIter::new()
145    }
146}
147
148impl ListIter {
149    // A new, empty list iterator.
150    pub fn new() -> Self {
151        ListIter::from_parts(().into(), 0, 0)
152    }
153
154    pub(crate) fn from_parts(robj: Robj, i: usize, len: usize) -> Self {
155        Self { robj, i, len }
156    }
157}
158
159impl Iterator for ListIter {
160    type Item = Robj;
161
162    fn size_hint(&self) -> (usize, Option<usize>) {
163        (self.len, Some(self.len))
164    }
165
166    fn next(&mut self) -> Option<Self::Item> {
167        let i = self.i;
168        self.i += 1;
169        if i >= self.len {
170            None
171        } else {
172            Some(unsafe { new_owned(VECTOR_ELT(self.robj.get(), i as isize)) })
173        }
174    }
175
176    fn nth(&mut self, n: usize) -> Option<Self::Item> {
177        self.i += n;
178        self.next()
179    }
180}
181
182impl ExactSizeIterator for ListIter {
183    /// Length of a list iterator.
184    fn len(&self) -> usize {
185        self.len - self.i
186    }
187}
188
189/// You can use the FromList wrapper to coerce a Robj into a list.
190/// ```
191/// use extendr_api::prelude::*;
192/// test! {
193///     let list = list!(1, 2);
194///     let vec : FromList<Vec<i32>> = list.try_into()?;
195///     assert_eq!(vec.0, vec![1, 2]);
196/// }
197/// ```
198pub struct FromList<T>(pub T);
199
200impl<T> TryFrom<Robj> for FromList<Vec<T>>
201where
202    T: TryFrom<Robj>,
203    <T as TryFrom<Robj>>::Error: Into<Error>,
204{
205    type Error = Error;
206
207    /// You can use the FromList wrapper to coerce a Robj into a list.
208    /// ```
209    /// use extendr_api::prelude::*;
210    /// test! {
211    ///     let list = list!(1, 2);
212    ///     let vec : FromList<Vec<i32>> = list.try_into()?;
213    ///     assert_eq!(vec.0, vec![1, 2]);
214    /// }
215    /// ```
216    fn try_from(robj: Robj) -> Result<Self> {
217        let listiter: ListIter = robj.try_into()?;
218        let res: Result<Vec<_>> = listiter
219            .map(|robj| T::try_from(robj).map_err(|e| e.into()))
220            .collect();
221        res.map(FromList)
222    }
223}
224
225impl TryFrom<Robj> for ListIter {
226    type Error = Error;
227
228    /// You can pass a ListIter to a function.
229    /// ```
230    /// use extendr_api::prelude::*;
231    /// test! {
232    ///     let list = list!(1, 2);
233    ///     let vec : ListIter = list.try_into()?;
234    ///     assert_eq!(vec.collect::<Vec<_>>(), vec![r!(1), r!(2)]);
235    /// }
236    /// ```
237    fn try_from(robj: Robj) -> Result<Self> {
238        let list: List = robj.try_into()?;
239        Ok(list.values())
240    }
241}
242
243impl From<ListIter> for Robj {
244    /// You can return a ListIter from a function.
245    /// ```
246    /// use extendr_api::prelude::*;
247    /// test! {
248    ///     let listiter = list!(1, 2).as_list().unwrap().values();
249    ///     assert_eq!(Robj::from(listiter), list!(1, 2));
250    /// }
251    /// ```
252    fn from(iter: ListIter) -> Self {
253        iter.robj
254    }
255}
256
257impl<'a> FromRobj<'a> for ListIter {
258    fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
259        robj.as_list().map(|l| l.values()).ok_or("Not a list.")
260    }
261}