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