miniextendr_api/into_r/
collections.rs1use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
7use std::hash::Hash;
8
9use crate::ffi::SexpExt;
10use crate::into_r::{IntoR, str_to_charsxp, str_to_charsxp_unchecked};
11
12macro_rules! impl_map_into_r {
13 ($(#[$meta:meta])* $map_ty:ident) => {
14 $(#[$meta])*
15 impl<V: IntoR> IntoR for $map_ty<String, V> {
16 type Error = crate::into_r_error::IntoRError;
17 fn try_into_sexp(self) -> Result<crate::ffi::SEXP, Self::Error> {
18 Ok(self.into_sexp())
19 }
20 unsafe fn try_into_sexp_unchecked(self) -> Result<crate::ffi::SEXP, Self::Error> {
21 Ok(unsafe { self.into_sexp_unchecked() })
22 }
23 fn into_sexp(self) -> crate::ffi::SEXP {
24 map_to_named_list(self.into_iter())
25 }
26 unsafe fn into_sexp_unchecked(self) -> crate::ffi::SEXP {
27 unsafe { map_to_named_list_unchecked(self.into_iter()) }
28 }
29 }
30 };
31}
32
33impl_map_into_r!(
34 HashMap
36);
37impl_map_into_r!(
38 BTreeMap
40);
41
42fn map_to_named_list<V: IntoR>(
44 iter: impl ExactSizeIterator<Item = (String, V)>,
45) -> crate::ffi::SEXP {
46 unsafe {
47 let n: crate::ffi::R_xlen_t = iter
48 .len()
49 .try_into()
50 .expect("map length exceeds isize::MAX");
51 let list = crate::ffi::Rf_allocVector(crate::ffi::SEXPTYPE::VECSXP, n);
52 crate::ffi::Rf_protect(list);
53
54 let names = crate::ffi::Rf_allocVector(crate::ffi::SEXPTYPE::STRSXP, n);
56 crate::ffi::Rf_protect(names);
57
58 for (i, (key, value)) in iter.enumerate() {
59 let idx: crate::ffi::R_xlen_t = i.try_into().expect("index exceeds isize::MAX");
60 list.set_vector_elt(idx, value.into_sexp());
62
63 let charsxp = str_to_charsxp(&key);
65 names.set_string_elt(idx, charsxp);
66 }
67
68 list.set_names(names);
70
71 crate::ffi::Rf_unprotect(2);
72 list
73 }
74}
75
76unsafe fn map_to_named_list_unchecked<V: IntoR>(
78 iter: impl ExactSizeIterator<Item = (String, V)>,
79) -> crate::ffi::SEXP {
80 unsafe {
81 let n: crate::ffi::R_xlen_t = iter
82 .len()
83 .try_into()
84 .expect("map length exceeds isize::MAX");
85 let list = crate::ffi::Rf_allocVector_unchecked(crate::ffi::SEXPTYPE::VECSXP, n);
86 crate::ffi::Rf_protect(list);
87
88 let names = crate::ffi::Rf_allocVector_unchecked(crate::ffi::SEXPTYPE::STRSXP, n);
89 crate::ffi::Rf_protect(names);
90
91 for (i, (key, value)) in iter.enumerate() {
92 let idx: crate::ffi::R_xlen_t = i.try_into().expect("index exceeds isize::MAX");
93 list.set_vector_elt_unchecked(idx, value.into_sexp_unchecked());
94
95 let charsxp = str_to_charsxp_unchecked(&key);
96 names.set_string_elt_unchecked(idx, charsxp);
97 }
98
99 list.set_attr_unchecked(crate::ffi::SEXP::names_symbol(), names);
100
101 crate::ffi::Rf_unprotect(2);
102 list
103 }
104}
105
106impl<T> IntoR for HashSet<T>
108where
109 T: crate::ffi::RNativeType + Eq + Hash,
110{
111 type Error = std::convert::Infallible;
112 fn try_into_sexp(self) -> Result<crate::ffi::SEXP, Self::Error> {
113 Ok(self.into_sexp())
114 }
115 unsafe fn try_into_sexp_unchecked(self) -> Result<crate::ffi::SEXP, Self::Error> {
116 Ok(unsafe { self.into_sexp_unchecked() })
117 }
118 fn into_sexp(self) -> crate::ffi::SEXP {
119 let vec: Vec<T> = self.into_iter().collect();
120 vec.into_sexp()
121 }
122 unsafe fn into_sexp_unchecked(self) -> crate::ffi::SEXP {
123 let vec: Vec<T> = self.into_iter().collect();
124 unsafe { vec.into_sexp_unchecked() }
125 }
126}
127
128impl<T> IntoR for BTreeSet<T>
130where
131 T: crate::ffi::RNativeType + Ord,
132{
133 type Error = std::convert::Infallible;
134 fn try_into_sexp(self) -> Result<crate::ffi::SEXP, Self::Error> {
135 Ok(self.into_sexp())
136 }
137 unsafe fn try_into_sexp_unchecked(self) -> Result<crate::ffi::SEXP, Self::Error> {
138 Ok(unsafe { self.into_sexp_unchecked() })
139 }
140 fn into_sexp(self) -> crate::ffi::SEXP {
141 let vec: Vec<T> = self.into_iter().collect();
142 vec.into_sexp()
143 }
144 unsafe fn into_sexp_unchecked(self) -> crate::ffi::SEXP {
145 let vec: Vec<T> = self.into_iter().collect();
146 unsafe { vec.into_sexp_unchecked() }
147 }
148}
149
150macro_rules! impl_set_string_into_r {
151 ($(#[$meta:meta])* $set_ty:ident) => {
152 $(#[$meta])*
153 impl IntoR for $set_ty<String> {
154 type Error = crate::into_r_error::IntoRError;
155 fn try_into_sexp(self) -> Result<crate::ffi::SEXP, Self::Error> {
156 Ok(self.into_sexp())
157 }
158 unsafe fn try_into_sexp_unchecked(self) -> Result<crate::ffi::SEXP, Self::Error> {
159 Ok(unsafe { self.into_sexp_unchecked() })
160 }
161 fn into_sexp(self) -> crate::ffi::SEXP {
162 let vec: Vec<String> = self.into_iter().collect();
163 vec.into_sexp()
164 }
165 unsafe fn into_sexp_unchecked(self) -> crate::ffi::SEXP {
166 let vec: Vec<String> = self.into_iter().collect();
167 unsafe { vec.into_sexp_unchecked() }
168 }
169 }
170 };
171}
172
173impl_set_string_into_r!(
174 HashSet
176);
177impl_set_string_into_r!(
178 BTreeSet
180);
181