extendr_api/wrapper/
lang.rs
1use super::*;
2use extendr_ffi::{R_NilValue, Rf_lcons, Rf_protect, Rf_unprotect};
3#[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}