extendr_api/wrapper/
list.rs

1use super::*;
2use crate::robj::Attributes;
3use extendr_ffi::{dataptr, R_xlen_t, SET_VECTOR_ELT, VECTOR_ELT};
4use std::iter::FromIterator;
5
6#[derive(PartialEq, Clone)]
7pub struct List {
8    pub(crate) robj: Robj,
9}
10
11impl Default for List {
12    fn default() -> Self {
13        List::new(0)
14    }
15}
16
17impl List {
18    /// Create a new list.
19    /// ```
20    /// use extendr_api::prelude::*;
21    /// test! {
22    ///     let list = List::new(10);
23    ///     assert_eq!(list.is_list(), true);
24    ///     assert_eq!(list.len(), 10);
25    /// }
26    /// ```
27    pub fn new(size: usize) -> Self {
28        let robj = Robj::alloc_vector(SEXPTYPE::VECSXP, size);
29        Self { robj }
30    }
31
32    /// Wrapper for creating a list (VECSXP) object.
33    /// ```
34    /// use extendr_api::prelude::*;
35    /// test! {
36    ///     let list = r!(List::from_values(&[r!(0), r!(1), r!(2)]));
37    ///     assert_eq!(list.is_list(), true);
38    ///     assert_eq!(list.len(), 3);
39    /// }
40    /// ```
41    pub fn from_values<V>(values: V) -> Self
42    where
43        V: IntoIterator,
44        V::IntoIter: ExactSizeIterator,
45        V::Item: Into<Robj>,
46    {
47        Self {
48            robj: make_vector(SEXPTYPE::VECSXP, values),
49        }
50    }
51
52    pub fn from_pairs<V>(pairs: V) -> Self
53    where
54        V: IntoIterator,
55        V::IntoIter: ExactSizeIterator + Clone,
56        V::Item: KeyValue,
57    {
58        let iter = pairs.into_iter();
59        let mut names = Vec::with_capacity(iter.len());
60        let mut values = Vec::with_capacity(iter.len());
61        for pair in iter {
62            names.push(pair.key());
63            values.push(pair.value());
64        }
65        let mut res = List::from_values(values);
66        res.as_robj_mut()
67            .set_names(names)
68            .unwrap()
69            .as_list()
70            .unwrap()
71    }
72
73    /// Wrapper for creating a list (VECSXP) object from an existing `HashMap`.
74    /// The `HashMap` is consumed.
75    /// ```
76    /// use extendr_api::prelude::*;
77    /// use std::collections::HashMap;
78    /// test! {
79    ///     let mut map: HashMap<&str, Robj> = HashMap::new();
80    ///     map.insert("a", r!(1));
81    ///     map.insert("b", r!(2));
82    ///
83    ///     let list = List::from_hashmap(map).unwrap();
84    ///     assert_eq!(list.is_list(), true);
85    ///
86    ///     let mut names : Vec<_> = list.names().unwrap().collect();
87    ///     names.sort();
88    ///     assert_eq!(names, vec!["a", "b"]);
89    /// }
90    /// ```
91    pub fn from_hashmap<K, V>(val: HashMap<K, V>) -> Result<Self>
92    where
93        V: IntoRobj,
94        K: Into<String>,
95    {
96        let (names, values): (Vec<_>, Vec<_>) = val
97            .into_iter()
98            .map(|(k, v)| (k.into(), v.into_robj()))
99            .unzip();
100        let mut res: Self = Self::from_values(values);
101        res.set_names(names)?;
102        Ok(res)
103    }
104
105    /// Build a list using separate names and values iterators.
106    /// Used internally by the `list!` macro.
107    pub fn from_names_and_values<N, V>(names: N, values: V) -> Result<Self>
108    where
109        N: IntoIterator,
110        N::IntoIter: ExactSizeIterator,
111        N::Item: ToVectorValue + AsRef<str>,
112        V: IntoIterator,
113        V::IntoIter: ExactSizeIterator,
114        V::Item: Into<Robj>,
115    {
116        let mut list = List::from_values(values);
117        list.set_names(names)?;
118        Ok(list)
119    }
120
121    /// Return an iterator over the values of this list.
122    /// ```
123    /// use extendr_api::prelude::*;
124    /// test! {
125    ///     let mut robj = list!(1, 2, 3);
126    ///     let objects : Vec<_> = robj.as_list().unwrap().values().collect();
127    ///     assert_eq!(objects, vec![r!(1), r!(2), r!(3)]);
128    /// }
129    /// ```
130    pub fn values(&self) -> ListIter {
131        ListIter::from_parts(self.robj.clone(), 0, self.robj.len())
132    }
133
134    /// Return an iterator over the names and values of this list.
135    /// ```
136    /// use extendr_api::prelude::*;
137    /// test! {
138    ///     let mut list = list!(a=1, 2);
139    ///     let names_and_values : Vec<_> = list.iter().collect();
140    ///     assert_eq!(names_and_values, vec![("a", r!(1)), ("", r!(2))]);
141    /// }
142    /// ```
143    pub fn iter(&self) -> NamedListIter {
144        // TODO: Make a proper NamedListIter.
145        self.names()
146            .map(|n| n.zip(self.values()))
147            .unwrap_or_else(|| StrIter::new(self.len()).zip(self.values()))
148    }
149
150    /// Get the list a slice of `Robj`s.
151    pub fn as_slice(&self) -> &[Robj] {
152        unsafe {
153            let data = dataptr(self.robj.get()) as *const Robj;
154            let len = self.robj.len();
155            std::slice::from_raw_parts(data, len)
156        }
157    }
158
159    /// Get a reference to an element in the list.
160    pub fn elt(&self, i: usize) -> Result<Robj> {
161        if i >= self.robj.len() {
162            Err(Error::OutOfRange(self.robj.clone()))
163        } else {
164            unsafe {
165                let sexp = VECTOR_ELT(self.robj.get(), i as R_xlen_t);
166                Ok(Robj::from_sexp(sexp))
167            }
168        }
169    }
170
171    /// Set an element in the list.
172    pub fn set_elt(&mut self, i: usize, value: Robj) -> Result<()> {
173        single_threaded(|| unsafe {
174            if i >= self.robj.len() {
175                Err(Error::OutOfRange(self.robj.clone()))
176            } else {
177                SET_VECTOR_ELT(self.robj.get_mut(), i as R_xlen_t, value.get());
178                Ok(())
179            }
180        })
181    }
182
183    /// Convert a `List` into a `HashMap`, consuming the list.
184    ///
185    /// - If an element doesn't have a name, an empty string (i.e. `""`) will be used as the key.
186    /// - If there are some duplicated names (including no name, which will be translated as `""`) of elements, only one of those will be preserved.
187    /// ```
188    /// use extendr_api::prelude::*;
189    /// use std::collections::HashMap;
190    /// test! {
191    ///     let mut robj = list!(a=1, 2);
192    ///     let names_and_values = robj.as_list().unwrap().into_hashmap();
193    ///     assert_eq!(names_and_values, vec![("a", r!(1)), ("", r!(2))].into_iter().collect::<HashMap<_, _>>());
194    /// }
195    /// ```
196    pub fn into_hashmap(self) -> HashMap<&'static str, Robj> {
197        self.as_robj().try_into().unwrap()
198    }
199}
200
201impl<T> TryFrom<&List> for HashMap<&str, T>
202where
203    T: TryFrom<Robj, Error = error::Error>,
204{
205    type Error = Error;
206
207    fn try_from(value: &List) -> Result<Self> {
208        let value = value
209            .iter()
210            .map(|(name, value)| -> Result<(&str, T)> { value.try_into().map(|x| (name, x)) })
211            .collect::<Result<HashMap<_, _>>>()?;
212
213        Ok(value)
214    }
215}
216
217impl<T> TryFrom<&List> for HashMap<String, T>
218where
219    T: TryFrom<Robj, Error = error::Error>,
220{
221    type Error = Error;
222    fn try_from(value: &List) -> Result<Self> {
223        let value: HashMap<&str, _> = value.try_into()?;
224        Ok(value.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
225    }
226}
227
228// The following is necessary because it is impossible to define `TryFrom<Robj> for &Robj` as
229// it requires returning a reference to a owned (moved) value
230
231impl TryFrom<&List> for HashMap<&str, Robj> {
232    type Error = Error;
233
234    fn try_from(value: &List) -> Result<Self> {
235        Ok(value.iter().collect())
236    }
237}
238
239impl TryFrom<&List> for HashMap<String, Robj> {
240    type Error = Error;
241    fn try_from(value: &List) -> Result<Self> {
242        let value: HashMap<&str, _> = value.try_into()?;
243        Ok(value.into_iter().map(|(k, v)| (k.to_string(), v)).collect())
244    }
245}
246
247impl IntoIterator for List {
248    type IntoIter = NamedListIter;
249    type Item = (&'static str, Robj);
250
251    /// Convert a List into an interator, consuming the list.
252    /// ```
253    /// use extendr_api::prelude::*;
254    /// test! {
255    ///     let list = list!(a=1, 2).as_list().unwrap();
256    ///     let vec : Vec<_> = list.into_iter().collect();
257    ///     assert_eq!(vec, vec![("a", r!(1)), ("", r!(2))]);
258    /// }
259    /// ```
260    fn into_iter(self) -> Self::IntoIter {
261        self.iter()
262    }
263}
264
265/// Iterator over the objects in a VECSXP, EXPRSXP or WEAKREFSXP.
266///
267/// ```
268/// use extendr_api::prelude::*;
269/// test! {
270///     let my_list = list!(a = 1, b = 2);
271///     let mut total = 0;
272///     for robj in my_list.as_list().unwrap().values() {
273///       if let Some(val) = robj.as_integer() {
274///         total += val;
275///       }
276///     }
277///     assert_eq!(total, 3);
278///
279///     for name in my_list.names().unwrap() {
280///        assert!(name == "a" || name == "b")
281///     }
282/// }
283/// ```
284#[derive(Clone)]
285pub struct ListIter {
286    robj: Robj,
287    i: usize,
288    len: usize,
289}
290
291impl Default for ListIter {
292    fn default() -> Self {
293        ListIter::new()
294    }
295}
296
297impl ListIter {
298    // A new, empty list iterator.
299    pub fn new() -> Self {
300        ListIter::from_parts(().into(), 0, 0)
301    }
302
303    pub(crate) fn from_parts(robj: Robj, i: usize, len: usize) -> Self {
304        Self { robj, i, len }
305    }
306}
307
308impl Iterator for ListIter {
309    type Item = Robj;
310
311    fn size_hint(&self) -> (usize, Option<usize>) {
312        (self.len, Some(self.len))
313    }
314
315    fn next(&mut self) -> Option<Self::Item> {
316        let i = self.i;
317        self.i += 1;
318        if i >= self.len {
319            None
320        } else {
321            Some(unsafe { Robj::from_sexp(VECTOR_ELT(self.robj.get(), i as isize)) })
322        }
323    }
324
325    fn nth(&mut self, n: usize) -> Option<Self::Item> {
326        self.i += n;
327        self.next()
328    }
329}
330
331impl ExactSizeIterator for ListIter {
332    /// Length of a list iterator.
333    fn len(&self) -> usize {
334        self.len - self.i
335    }
336}
337
338/// You can use the FromList wrapper to coerce a Robj into a list.
339/// ```
340/// use extendr_api::prelude::*;
341/// test! {
342///     let list = Robj::from(list!(1, 2));
343///     let vec : FromList<Vec<i32>> = list.try_into()?;
344///     assert_eq!(vec.0, vec![1, 2]);
345/// }
346/// ```
347pub struct FromList<T>(pub T);
348
349impl<T> TryFrom<&Robj> for FromList<Vec<T>>
350where
351    T: TryFrom<Robj>,
352    <T as TryFrom<Robj>>::Error: Into<Error>,
353{
354    type Error = Error;
355
356    fn try_from(robj: &Robj) -> Result<Self> {
357        let listiter: ListIter = robj.try_into()?;
358        let res: Result<Vec<_>> = listiter
359            .map(|robj| T::try_from(robj).map_err(|e| e.into()))
360            .collect();
361        res.map(FromList)
362    }
363}
364
365impl<T> TryFrom<Robj> for FromList<Vec<T>>
366where
367    T: TryFrom<Robj>,
368    <T as TryFrom<Robj>>::Error: Into<Error>,
369{
370    type Error = Error;
371
372    fn try_from(robj: Robj) -> Result<Self> {
373        <FromList<Vec<T>>>::try_from(&robj)
374    }
375}
376
377impl TryFrom<&Robj> for ListIter {
378    type Error = Error;
379
380    /// Convert a general R object into a List iterator if possible.
381    fn try_from(robj: &Robj) -> Result<Self> {
382        let list: List = robj.try_into()?;
383        Ok(list.values())
384    }
385}
386
387impl TryFrom<Robj> for ListIter {
388    type Error = Error;
389
390    /// Convert a general R object into a List iterator if possible.
391    fn try_from(robj: Robj) -> Result<Self> {
392        <ListIter>::try_from(&robj)
393    }
394}
395
396impl From<ListIter> for Robj {
397    /// You can return a ListIter from a function.
398    /// ```
399    /// use extendr_api::prelude::*;
400    /// test! {
401    ///     let listiter = list!(1, 2).values();
402    ///     assert_eq!(Robj::from(listiter), Robj::from(list!(1, 2)));
403    /// }
404    /// ```
405    fn from(iter: ListIter) -> Self {
406        iter.robj
407    }
408}
409
410// TODO: use Rstr or Sym instead of String.
411pub trait KeyValue {
412    fn key(&self) -> String;
413    fn value(self) -> Robj;
414}
415
416impl<T: AsRef<str>> KeyValue for (T, Robj) {
417    fn key(&self) -> String {
418        self.0.as_ref().to_owned()
419    }
420    fn value(self) -> Robj {
421        self.1
422    }
423}
424
425impl<T: Into<Robj>> FromIterator<T> for List {
426    /// Convert an iterator to a `List` object.
427    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
428        let iter_collect: Vec<_> = iter.into_iter().collect();
429        let len = iter_collect.len();
430
431        crate::single_threaded(|| unsafe {
432            let mut robj = Robj::alloc_vector(SEXPTYPE::VECSXP, len);
433            for (i, v) in iter_collect.into_iter().enumerate() {
434                // We don't PROTECT each element here, as they will be immediately
435                // placed into a list which will protect them:
436                // https://cran.r-project.org/doc/manuals/R-exts.html#Garbage-Collection
437                // note: Currently, `Robj` automatically registers `v` by the
438                // `ownership`-module, making it protected, even though it isn't necessary to do so.
439                let item: Robj = v.into();
440                SET_VECTOR_ELT(robj.get_mut(), i as isize, item.get());
441            }
442
443            List { robj }
444        })
445    }
446}
447
448impl Attributes for List {}
449
450impl Deref for List {
451    type Target = [Robj];
452
453    /// Lists behave like slices of Robj.
454    fn deref(&self) -> &Self::Target {
455        self.as_slice()
456    }
457}
458
459impl std::fmt::Debug for List {
460    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
461        if self.names().is_none() {
462            write!(
463                f,
464                "list!({})",
465                self.values()
466                    .map(|v| format!("{:?}", v))
467                    .collect::<Vec<_>>()
468                    .join(", ")
469            )
470        } else {
471            write!(
472                f,
473                "list!({})",
474                self.iter()
475                    .map(|(k, v)| if !k.is_empty() {
476                        format!("{}={:?}", k, v)
477                    } else {
478                        format!("{:?}", v)
479                    })
480                    .collect::<Vec<_>>()
481                    .join(", ")
482            )
483        }
484    }
485}