miniextendr_api/from_r/
cow_and_paths.rs1use std::borrow::Cow;
9use std::collections::{BTreeSet, HashSet};
10use std::ffi::OsString;
11use std::path::PathBuf;
12
13use crate::ffi::{SEXP, SEXPTYPE, SexpExt};
14use crate::from_r::{SexpError, SexpTypeError, TryFromSexp, charsxp_to_cow, charsxp_to_str};
15
16impl<T> TryFromSexp for Cow<'static, [T]>
26where
27 T: crate::ffi::RNativeType + Copy + Clone,
28{
29 type Error = SexpTypeError;
30
31 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
32 let slice: &[T] = TryFromSexp::try_from_sexp(sexp)?;
33 Ok(Cow::Borrowed(slice))
34 }
35
36 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
37 let slice: &[T] = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
38 Ok(Cow::Borrowed(slice))
39 }
40}
41
42impl TryFromSexp for Cow<'static, str> {
52 type Error = SexpError;
53
54 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
55 let s: &'static str = TryFromSexp::try_from_sexp(sexp)?;
56 Ok(Cow::Borrowed(s))
57 }
58
59 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
60 let s: &'static str = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
61 Ok(Cow::Borrowed(s))
62 }
63}
64
65impl TryFromSexp for Vec<Cow<'static, str>> {
76 type Error = SexpError;
77
78 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
79 let actual = sexp.type_of();
80 if actual != SEXPTYPE::STRSXP {
81 return Err(SexpTypeError {
82 expected: SEXPTYPE::STRSXP,
83 actual,
84 }
85 .into());
86 }
87
88 let len = sexp.len();
89 let mut result = Vec::with_capacity(len);
90
91 for i in 0..len {
92 let charsxp = sexp.string_elt(i as crate::ffi::R_xlen_t);
93 if charsxp == SEXP::na_string() || charsxp == SEXP::blank_string() {
94 result.push(Cow::Borrowed(""));
95 } else {
96 result.push(unsafe { charsxp_to_cow(charsxp) });
97 }
98 }
99
100 Ok(result)
101 }
102}
103
104impl TryFromSexp for Vec<Option<Cow<'static, str>>> {
108 type Error = SexpError;
109
110 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
111 let actual = sexp.type_of();
112 if actual != SEXPTYPE::STRSXP {
113 return Err(SexpTypeError {
114 expected: SEXPTYPE::STRSXP,
115 actual,
116 }
117 .into());
118 }
119
120 let len = sexp.len();
121 let mut result = Vec::with_capacity(len);
122
123 for i in 0..len {
124 let charsxp = sexp.string_elt(i as crate::ffi::R_xlen_t);
125 if charsxp == SEXP::na_string() {
126 result.push(None);
127 } else {
128 result.push(Some(unsafe { charsxp_to_cow(charsxp) }));
130 }
131 }
132
133 Ok(result)
134 }
135}
136
137impl TryFromSexp for Box<[Cow<'static, str>]> {
141 type Error = SexpError;
142
143 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
144 let vec: Vec<Cow<'static, str>> = TryFromSexp::try_from_sexp(sexp)?;
145 Ok(vec.into_boxed_slice())
146 }
147}
148
149impl TryFromSexp for Vec<String> {
168 type Error = SexpError;
169
170 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
171 let actual = sexp.type_of();
172 if actual != SEXPTYPE::STRSXP {
173 return Err(SexpTypeError {
174 expected: SEXPTYPE::STRSXP,
175 actual,
176 }
177 .into());
178 }
179
180 let len = sexp.len();
181 let mut result = Vec::with_capacity(len);
182
183 for i in 0..len {
184 let charsxp = sexp.string_elt(i as crate::ffi::R_xlen_t);
185 let s = if charsxp == SEXP::na_string() {
186 String::new()
187 } else {
188 unsafe { charsxp_to_str(charsxp) }.to_owned()
189 };
190 result.push(s);
191 }
192
193 Ok(result)
194 }
195}
196
197impl TryFromSexp for Box<[String]> {
201 type Error = SexpError;
202
203 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
204 let vec: Vec<String> = TryFromSexp::try_from_sexp(sexp)?;
205 Ok(vec.into_boxed_slice())
206 }
207}
208
209impl TryFromSexp for Vec<&'static str> {
213 type Error = SexpError;
214
215 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
216 let actual = sexp.type_of();
217 if actual != SEXPTYPE::STRSXP {
218 return Err(SexpTypeError {
219 expected: SEXPTYPE::STRSXP,
220 actual,
221 }
222 .into());
223 }
224
225 let len = sexp.len();
226 let mut result = Vec::with_capacity(len);
227
228 for i in 0..len {
229 let charsxp = sexp.string_elt(i as crate::ffi::R_xlen_t);
230 if charsxp == SEXP::na_string() {
231 result.push("");
232 continue;
233 }
234 if charsxp == SEXP::blank_string() {
235 result.push("");
236 continue;
237 }
238 result.push(unsafe { charsxp_to_str(charsxp) });
239 }
240
241 Ok(result)
242 }
243}
244
245impl TryFromSexp for Vec<Option<&'static str>> {
247 type Error = SexpError;
248
249 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
250 let actual = sexp.type_of();
251 if actual != SEXPTYPE::STRSXP {
252 return Err(SexpTypeError {
253 expected: SEXPTYPE::STRSXP,
254 actual,
255 }
256 .into());
257 }
258
259 let len = sexp.len();
260 let mut result = Vec::with_capacity(len);
261
262 for i in 0..len {
263 let charsxp = sexp.string_elt(i as crate::ffi::R_xlen_t);
264 if charsxp == SEXP::na_string() {
265 result.push(None);
266 continue;
267 }
268 if charsxp == SEXP::blank_string() {
269 result.push(Some(""));
270 continue;
271 }
272 result.push(Some(unsafe { charsxp_to_str(charsxp) }));
273 }
274
275 Ok(result)
276 }
277}
278
279macro_rules! impl_set_string_try_from_sexp {
280 ($(#[$meta:meta])* $set_ty:ident) => {
281 $(#[$meta])*
282 impl TryFromSexp for $set_ty<String> {
283 type Error = SexpError;
284
285 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
286 let vec: Vec<String> = TryFromSexp::try_from_sexp(sexp)?;
287 Ok(vec.into_iter().collect())
288 }
289 }
290 };
291}
292
293impl_set_string_try_from_sexp!(
294 HashSet
296);
297impl_set_string_try_from_sexp!(
298 BTreeSet
300);
301macro_rules! impl_string_wrapper_try_from_sexp {
308 (
309 $(#[$scalar_meta:meta])*
310 scalar: $ty:ty;
311 $(#[$option_meta:meta])*
312 option: $ty2:ty;
313 $(#[$vec_meta:meta])*
314 vec: $ty3:ty;
315 $(#[$vec_option_meta:meta])*
316 vec_option: $ty4:ty;
317 ) => {
318 $(#[$scalar_meta])*
319 impl TryFromSexp for $ty {
320 type Error = SexpError;
321
322 #[inline]
323 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
324 let s: String = TryFromSexp::try_from_sexp(sexp)?;
325 Ok(<$ty>::from(s))
326 }
327
328 #[inline]
329 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
330 let s: String = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
331 Ok(<$ty>::from(s))
332 }
333 }
334
335 $(#[$option_meta])*
336 impl TryFromSexp for Option<$ty> {
337 type Error = SexpError;
338
339 #[inline]
340 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
341 let opt: Option<String> = TryFromSexp::try_from_sexp(sexp)?;
342 Ok(opt.map(<$ty>::from))
343 }
344
345 #[inline]
346 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
347 let opt: Option<String> = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
348 Ok(opt.map(<$ty>::from))
349 }
350 }
351
352 $(#[$vec_meta])*
353 impl TryFromSexp for Vec<$ty> {
354 type Error = SexpError;
355
356 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
357 let vec: Vec<String> = TryFromSexp::try_from_sexp(sexp)?;
358 Ok(vec.into_iter().map(<$ty>::from).collect())
359 }
360
361 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
362 let vec: Vec<String> = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
363 Ok(vec.into_iter().map(<$ty>::from).collect())
364 }
365 }
366
367 $(#[$vec_option_meta])*
368 impl TryFromSexp for Vec<Option<$ty>> {
369 type Error = SexpError;
370
371 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
372 let vec: Vec<Option<String>> = TryFromSexp::try_from_sexp(sexp)?;
373 Ok(vec.into_iter().map(|opt| opt.map(<$ty>::from)).collect())
374 }
375
376 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
377 let vec: Vec<Option<String>> = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
378 Ok(vec.into_iter().map(|opt| opt.map(<$ty>::from)).collect())
379 }
380 }
381 };
382}
383
384impl_string_wrapper_try_from_sexp!(
385 scalar: PathBuf;
392 option: PathBuf;
394 vec: PathBuf;
401 vec_option: PathBuf;
405);
406
407impl_string_wrapper_try_from_sexp!(
408 scalar: OsString;
418 option: OsString;
420 vec: OsString;
427 vec_option: OsString;
431);
432