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>> {
75 type Error = SexpError;
76
77 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
78 let actual = sexp.type_of();
79 if actual != SEXPTYPE::STRSXP {
80 return Err(SexpTypeError {
81 expected: SEXPTYPE::STRSXP,
82 actual,
83 }
84 .into());
85 }
86
87 let len = sexp.len();
88 let mut result = Vec::with_capacity(len);
89
90 for i in 0..len {
91 let charsxp = sexp.string_elt(i as crate::ffi::R_xlen_t);
92 if charsxp == SEXP::na_string() || charsxp == SEXP::blank_string() {
93 result.push(Cow::Borrowed(""));
94 } else {
95 result.push(unsafe { charsxp_to_cow(charsxp) });
96 }
97 }
98
99 Ok(result)
100 }
101}
102
103impl TryFromSexp for Vec<Option<Cow<'static, str>>> {
107 type Error = SexpError;
108
109 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
110 let actual = sexp.type_of();
111 if actual != SEXPTYPE::STRSXP {
112 return Err(SexpTypeError {
113 expected: SEXPTYPE::STRSXP,
114 actual,
115 }
116 .into());
117 }
118
119 let len = sexp.len();
120 let mut result = Vec::with_capacity(len);
121
122 for i in 0..len {
123 let charsxp = sexp.string_elt(i as crate::ffi::R_xlen_t);
124 if charsxp == SEXP::na_string() {
125 result.push(None);
126 } else {
127 result.push(Some(unsafe { charsxp_to_cow(charsxp) }));
129 }
130 }
131
132 Ok(result)
133 }
134}
135
136impl TryFromSexp for Box<[Cow<'static, str>]> {
140 type Error = SexpError;
141
142 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
143 let vec: Vec<Cow<'static, str>> = TryFromSexp::try_from_sexp(sexp)?;
144 Ok(vec.into_boxed_slice())
145 }
146}
147
148impl TryFromSexp for Vec<String> {
167 type Error = SexpError;
168
169 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
170 use crate::ffi::Rf_translateCharUTF8;
171
172 let actual = sexp.type_of();
173 if actual != SEXPTYPE::STRSXP {
174 return Err(SexpTypeError {
175 expected: SEXPTYPE::STRSXP,
176 actual,
177 }
178 .into());
179 }
180
181 let len = sexp.len();
182 let mut result = Vec::with_capacity(len);
183
184 for i in 0..len {
185 let charsxp = sexp.string_elt(i as crate::ffi::R_xlen_t);
186 let s = if charsxp == SEXP::na_string() {
187 String::new()
188 } else {
189 let c_str = unsafe { Rf_translateCharUTF8(charsxp) };
190 if c_str.is_null() {
191 String::new()
192 } else {
193 unsafe { std::ffi::CStr::from_ptr(c_str) }
194 .to_str()
195 .unwrap_or("")
196 .to_owned()
197 }
198 };
199 result.push(s);
200 }
201
202 Ok(result)
203 }
204}
205
206impl TryFromSexp for Box<[String]> {
210 type Error = SexpError;
211
212 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
213 let vec: Vec<String> = TryFromSexp::try_from_sexp(sexp)?;
214 Ok(vec.into_boxed_slice())
215 }
216}
217
218impl TryFromSexp for Vec<&'static str> {
222 type Error = SexpError;
223
224 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
225 let actual = sexp.type_of();
226 if actual != SEXPTYPE::STRSXP {
227 return Err(SexpTypeError {
228 expected: SEXPTYPE::STRSXP,
229 actual,
230 }
231 .into());
232 }
233
234 let len = sexp.len();
235 let mut result = Vec::with_capacity(len);
236
237 for i in 0..len {
238 let charsxp = sexp.string_elt(i as crate::ffi::R_xlen_t);
239 if charsxp == SEXP::na_string() {
240 result.push("");
241 continue;
242 }
243 if charsxp == SEXP::blank_string() {
244 result.push("");
245 continue;
246 }
247 result.push(unsafe { charsxp_to_str(charsxp) });
248 }
249
250 Ok(result)
251 }
252}
253
254impl TryFromSexp for Vec<Option<&'static str>> {
256 type Error = SexpError;
257
258 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
259 let actual = sexp.type_of();
260 if actual != SEXPTYPE::STRSXP {
261 return Err(SexpTypeError {
262 expected: SEXPTYPE::STRSXP,
263 actual,
264 }
265 .into());
266 }
267
268 let len = sexp.len();
269 let mut result = Vec::with_capacity(len);
270
271 for i in 0..len {
272 let charsxp = sexp.string_elt(i as crate::ffi::R_xlen_t);
273 if charsxp == SEXP::na_string() {
274 result.push(None);
275 continue;
276 }
277 if charsxp == SEXP::blank_string() {
278 result.push(Some(""));
279 continue;
280 }
281 result.push(Some(unsafe { charsxp_to_str(charsxp) }));
282 }
283
284 Ok(result)
285 }
286}
287
288macro_rules! impl_set_string_try_from_sexp {
289 ($(#[$meta:meta])* $set_ty:ident) => {
290 $(#[$meta])*
291 impl TryFromSexp for $set_ty<String> {
292 type Error = SexpError;
293
294 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
295 let vec: Vec<String> = TryFromSexp::try_from_sexp(sexp)?;
296 Ok(vec.into_iter().collect())
297 }
298 }
299 };
300}
301
302impl_set_string_try_from_sexp!(
303 HashSet
305);
306impl_set_string_try_from_sexp!(
307 BTreeSet
309);
310macro_rules! impl_string_wrapper_try_from_sexp {
317 (
318 $(#[$scalar_meta:meta])*
319 scalar: $ty:ty;
320 $(#[$option_meta:meta])*
321 option: $ty2:ty;
322 $(#[$vec_meta:meta])*
323 vec: $ty3:ty;
324 $(#[$vec_option_meta:meta])*
325 vec_option: $ty4:ty;
326 ) => {
327 $(#[$scalar_meta])*
328 impl TryFromSexp for $ty {
329 type Error = SexpError;
330
331 #[inline]
332 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
333 let s: String = TryFromSexp::try_from_sexp(sexp)?;
334 Ok(<$ty>::from(s))
335 }
336
337 #[inline]
338 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
339 let s: String = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
340 Ok(<$ty>::from(s))
341 }
342 }
343
344 $(#[$option_meta])*
345 impl TryFromSexp for Option<$ty> {
346 type Error = SexpError;
347
348 #[inline]
349 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
350 let opt: Option<String> = TryFromSexp::try_from_sexp(sexp)?;
351 Ok(opt.map(<$ty>::from))
352 }
353
354 #[inline]
355 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
356 let opt: Option<String> = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
357 Ok(opt.map(<$ty>::from))
358 }
359 }
360
361 $(#[$vec_meta])*
362 impl TryFromSexp for Vec<$ty> {
363 type Error = SexpError;
364
365 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
366 let vec: Vec<String> = TryFromSexp::try_from_sexp(sexp)?;
367 Ok(vec.into_iter().map(<$ty>::from).collect())
368 }
369
370 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
371 let vec: Vec<String> = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
372 Ok(vec.into_iter().map(<$ty>::from).collect())
373 }
374 }
375
376 $(#[$vec_option_meta])*
377 impl TryFromSexp for Vec<Option<$ty>> {
378 type Error = SexpError;
379
380 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
381 let vec: Vec<Option<String>> = TryFromSexp::try_from_sexp(sexp)?;
382 Ok(vec.into_iter().map(|opt| opt.map(<$ty>::from)).collect())
383 }
384
385 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
386 let vec: Vec<Option<String>> = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
387 Ok(vec.into_iter().map(|opt| opt.map(<$ty>::from)).collect())
388 }
389 }
390 };
391}
392
393impl_string_wrapper_try_from_sexp!(
394 scalar: PathBuf;
401 option: PathBuf;
403 vec: PathBuf;
410 vec_option: PathBuf;
414);
415
416impl_string_wrapper_try_from_sexp!(
417 scalar: OsString;
427 option: OsString;
429 vec: OsString;
436 vec_option: OsString;
440);
441