extendr_api/wrapper/
lang.rs

1use super::*;
2use extendr_ffi::{R_NilValue, Rf_lcons, Rf_protect, Rf_unprotect};
3/// Wrapper for creating language objects.
4/// ```
5/// use extendr_api::prelude::*;
6/// test! {
7///     let call_to_xyz = r!(Language::from_values(&[sym!(xyz), r!(1), r!(2)]));
8///     assert_eq!(call_to_xyz.is_language(), true);
9///     assert_eq!(call_to_xyz.len(), 3);
10/// }
11/// ```
12///
13/// Note: You can use the [lang!] macro for this.
14#[derive(PartialEq, Clone)]
15pub struct Language {
16    pub(crate) robj: Robj,
17}
18
19impl Language {
20    pub fn from_values<T>(values: T) -> Self
21    where
22        T: IntoIterator,
23        T::IntoIter: DoubleEndedIterator,
24        T::Item: Into<Robj>,
25    {
26        single_threaded(|| unsafe {
27            let mut res = R_NilValue;
28            let mut num_protected = 0;
29            for val in values.into_iter().rev() {
30                let val = Rf_protect(val.into().get());
31                res = Rf_protect(Rf_lcons(val, res));
32                num_protected += 2;
33            }
34            let robj = Robj::from_sexp(res);
35            Rf_unprotect(num_protected);
36            Language { robj }
37        })
38    }
39
40    pub fn iter(&self) -> PairlistIter {
41        unsafe {
42            PairlistIter {
43                robj: self.robj.clone(),
44                list_elem: self.robj.get(),
45            }
46        }
47    }
48
49    pub fn names(&self) -> impl Iterator<Item = &'static str> {
50        self.iter().map(|(tag, _)| tag)
51    }
52
53    pub fn values(&self) -> impl Iterator<Item = Robj> {
54        self.iter().map(|(_, robj)| robj)
55    }
56}
57
58impl std::fmt::Debug for Language {
59    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60        write!(
61            f,
62            "lang!({})",
63            self.iter()
64                .map(|(k, v)| if k.is_empty() {
65                    format!("{:?}", v)
66                } else {
67                    format!("{}={:?}", k, v)
68                })
69                .collect::<Vec<_>>()
70                .join(", ")
71        )?;
72        Ok(())
73    }
74}