miniextendr_api/from_r/
cow_and_paths.rs1use std::borrow::Cow;
17use std::collections::{BTreeSet, HashSet};
18use std::ffi::OsString;
19use std::path::PathBuf;
20
21use crate::SEXP;
22use crate::from_r::{SexpError, SexpTypeError, TryFromSexp, charsxp_to_str, map_strsxp_with};
23
24impl<T: crate::RNativeType> TryFromSexp for Cow<'_, [T]> {
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::Owned(slice.to_vec()))
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::Owned(slice.to_vec()))
39 }
40}
41
42impl TryFromSexp for Cow<'_, str> {
47 type Error = SexpError;
48 const CHARACTER_ONLY: bool = true;
49
50 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
51 String::try_from_sexp(sexp).map(Cow::Owned)
52 }
53
54 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
55 unsafe { String::try_from_sexp_unchecked(sexp) }.map(Cow::Owned)
56 }
57}
58
59impl TryFromSexp for Vec<Cow<'_, str>> {
62 type Error = SexpError;
63 const CHARACTER_ONLY: bool = true;
64
65 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
66 Vec::<String>::try_from_sexp(sexp)
67 .map(|values| values.into_iter().map(Cow::Owned).collect())
68 }
69}
70
71impl TryFromSexp for Vec<Option<Cow<'_, str>>> {
74 type Error = SexpError;
75 const CHARACTER_ONLY: bool = true;
76
77 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
78 Vec::<Option<String>>::try_from_sexp(sexp)
79 .map(|values| values.into_iter().map(|v| v.map(Cow::Owned)).collect())
80 }
81}
82
83impl TryFromSexp for Vec<String> {
102 type Error = SexpError;
103 const CHARACTER_ONLY: bool = true;
104
105 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
106 map_strsxp_with(sexp, |charsxp, _i| {
107 let s = if charsxp == SEXP::na_string() {
108 String::new()
109 } else {
110 unsafe { charsxp_to_str(charsxp) }.to_owned()
111 };
112 Ok(s)
113 })
114 }
115}
116
117impl TryFromSexp for Vec<&'static str> {
121 type Error = SexpError;
122 const CHARACTER_ONLY: bool = true;
123
124 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
125 map_strsxp_with(sexp, |charsxp, _i| {
126 if charsxp == SEXP::na_string() || charsxp == SEXP::blank_string() {
127 return Ok("");
128 }
129 Ok(unsafe { charsxp_to_str(charsxp) })
130 })
131 }
132}
133
134impl TryFromSexp for Vec<Option<&'static str>> {
136 type Error = SexpError;
137 const CHARACTER_ONLY: bool = true;
138
139 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
140 map_strsxp_with(sexp, |charsxp, _i| {
141 if charsxp == SEXP::na_string() {
142 return Ok(None);
143 }
144 if charsxp == SEXP::blank_string() {
145 return Ok(Some(""));
146 }
147 Ok(Some(unsafe { charsxp_to_str(charsxp) }))
148 })
149 }
150}
151
152macro_rules! impl_set_string_try_from_sexp {
153 ($(#[$meta:meta])* $set_ty:ident) => {
154 $(#[$meta])*
155 impl TryFromSexp for $set_ty<String> {
156 type Error = SexpError;
157 const CHARACTER_ONLY: bool = true;
158
159 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
160 let vec: Vec<String> = TryFromSexp::try_from_sexp(sexp)?;
161 Ok(vec.into_iter().collect())
162 }
163 }
164 };
165}
166
167#[doc = r" Convert R character vector to `HashSet<String>`."]
impl TryFromSexp for HashSet<String> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let vec: Vec<String> = TryFromSexp::try_from_sexp(sexp)?;
Ok(vec.into_iter().collect())
}
}impl_set_string_try_from_sexp!(
168 HashSet
170);
171#[doc = r" Convert R character vector to `BTreeSet<String>`."]
impl TryFromSexp for BTreeSet<String> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let vec: Vec<String> = TryFromSexp::try_from_sexp(sexp)?;
Ok(vec.into_iter().collect())
}
}impl_set_string_try_from_sexp!(
172 BTreeSet
174);
175macro_rules! impl_string_wrapper_try_from_sexp {
182 (
183 $(#[$scalar_meta:meta])*
184 scalar: $ty:ty;
185 $(#[$option_meta:meta])*
186 option: $ty2:ty;
187 $(#[$vec_meta:meta])*
188 vec: $ty3:ty;
189 $(#[$vec_option_meta:meta])*
190 vec_option: $ty4:ty;
191 ) => {
192 $(#[$scalar_meta])*
193 impl TryFromSexp for $ty {
194 type Error = SexpError;
195 const CHARACTER_ONLY: bool = true;
196
197 #[inline]
198 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
199 let s: String = TryFromSexp::try_from_sexp(sexp)?;
200 Ok(<$ty>::from(s))
201 }
202
203 #[inline]
204 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
205 let s: String = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
206 Ok(<$ty>::from(s))
207 }
208 }
209
210 $(#[$option_meta])*
211 impl TryFromSexp for Option<$ty> {
212 type Error = SexpError;
213 const CHARACTER_ONLY: bool = true;
214
215 #[inline]
216 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
217 let opt: Option<String> = TryFromSexp::try_from_sexp(sexp)?;
218 Ok(opt.map(<$ty>::from))
219 }
220
221 #[inline]
222 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
223 let opt: Option<String> = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
224 Ok(opt.map(<$ty>::from))
225 }
226 }
227
228 $(#[$vec_meta])*
229 impl TryFromSexp for Vec<$ty> {
230 type Error = SexpError;
231 const CHARACTER_ONLY: bool = true;
232
233 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
234 let vec: Vec<String> = TryFromSexp::try_from_sexp(sexp)?;
235 Ok(vec.into_iter().map(<$ty>::from).collect())
236 }
237
238 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
239 let vec: Vec<String> = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
240 Ok(vec.into_iter().map(<$ty>::from).collect())
241 }
242 }
243
244 $(#[$vec_option_meta])*
245 impl TryFromSexp for Vec<Option<$ty>> {
246 type Error = SexpError;
247 const CHARACTER_ONLY: bool = true;
248
249 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
250 let vec: Vec<Option<String>> = TryFromSexp::try_from_sexp(sexp)?;
251 Ok(vec.into_iter().map(|opt| opt.map(<$ty>::from)).collect())
252 }
253
254 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
255 let vec: Vec<Option<String>> = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
256 Ok(vec.into_iter().map(|opt| opt.map(<$ty>::from)).collect())
257 }
258 }
259 };
260}
261
262#[doc = r" Convert R character scalar (STRSXP of length 1) to `PathBuf`."]
#[doc = r""]
#[doc = r" # NA Handling"]
#[doc = r""]
#[doc =
r#" **Warning:** `NA_character_` is converted to empty path `""`. This is lossy!"#]
#[doc =
r" If you need to distinguish between NA and empty strings, use `Option<PathBuf>` instead."]
impl TryFromSexp for PathBuf {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
#[inline]
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let s: String = TryFromSexp::try_from_sexp(sexp)?;
Ok(<PathBuf>::from(s))
}
#[inline]
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
let s: String =
unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
Ok(<PathBuf>::from(s))
}
}
#[doc =
r" NA-aware PathBuf conversion: returns `None` for `NA_character_` or `NULL`."]
impl TryFromSexp for Option<PathBuf> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
#[inline]
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let opt: Option<String> = TryFromSexp::try_from_sexp(sexp)?;
Ok(opt.map(<PathBuf>::from))
}
#[inline]
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
let opt: Option<String> =
unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
Ok(opt.map(<PathBuf>::from))
}
}
#[doc = r" Convert R character vector (STRSXP) to `Vec<PathBuf>`."]
#[doc = r""]
#[doc = r" # NA Handling"]
#[doc = r""]
#[doc =
r" **Warning:** `NA_character_` elements are converted to empty paths."]
#[doc = r" Use `Vec<Option<PathBuf>>` if you need to preserve NA values."]
impl TryFromSexp for Vec<PathBuf> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let vec: Vec<String> = TryFromSexp::try_from_sexp(sexp)?;
Ok(vec.into_iter().map(<PathBuf>::from).collect())
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
let vec: Vec<String> =
unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
Ok(vec.into_iter().map(<PathBuf>::from).collect())
}
}
#[doc =
r" Convert R character vector (STRSXP) to `Vec<Option<PathBuf>>` with NA support."]
#[doc = r""]
#[doc = r" `NA_character_` elements are converted to `None`."]
impl TryFromSexp for Vec<Option<PathBuf>> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let vec: Vec<Option<String>> = TryFromSexp::try_from_sexp(sexp)?;
Ok(vec.into_iter().map(|opt| opt.map(<PathBuf>::from)).collect())
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
let vec: Vec<Option<String>> =
unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
Ok(vec.into_iter().map(|opt| opt.map(<PathBuf>::from)).collect())
}
}impl_string_wrapper_try_from_sexp!(
263 scalar: PathBuf;
270 option: PathBuf;
272 vec: PathBuf;
279 vec_option: PathBuf;
283);
284
285#[doc = r" Convert R character scalar (STRSXP of length 1) to `OsString`."]
#[doc = r""]
#[doc =
r" Since R strings are converted to UTF-8, the resulting `OsString` contains"]
#[doc = r" valid UTF-8 data."]
#[doc = r""]
#[doc = r" # NA Handling"]
#[doc = r""]
#[doc =
r" **Warning:** `NA_character_` is converted to empty string. This is lossy!"]
#[doc =
r" If you need to distinguish between NA and empty strings, use `Option<OsString>` instead."]
impl TryFromSexp for OsString {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
#[inline]
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let s: String = TryFromSexp::try_from_sexp(sexp)?;
Ok(<OsString>::from(s))
}
#[inline]
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
let s: String =
unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
Ok(<OsString>::from(s))
}
}
#[doc =
r" NA-aware OsString conversion: returns `None` for `NA_character_` or `NULL`."]
impl TryFromSexp for Option<OsString> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
#[inline]
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let opt: Option<String> = TryFromSexp::try_from_sexp(sexp)?;
Ok(opt.map(<OsString>::from))
}
#[inline]
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
let opt: Option<String> =
unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
Ok(opt.map(<OsString>::from))
}
}
#[doc = r" Convert R character vector (STRSXP) to `Vec<OsString>`."]
#[doc = r""]
#[doc = r" # NA Handling"]
#[doc = r""]
#[doc =
r" **Warning:** `NA_character_` elements are converted to empty strings."]
#[doc = r" Use `Vec<Option<OsString>>` if you need to preserve NA values."]
impl TryFromSexp for Vec<OsString> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let vec: Vec<String> = TryFromSexp::try_from_sexp(sexp)?;
Ok(vec.into_iter().map(<OsString>::from).collect())
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
let vec: Vec<String> =
unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
Ok(vec.into_iter().map(<OsString>::from).collect())
}
}
#[doc =
r" Convert R character vector (STRSXP) to `Vec<Option<OsString>>` with NA support."]
#[doc = r""]
#[doc = r" `NA_character_` elements are converted to `None`."]
impl TryFromSexp for Vec<Option<OsString>> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
let vec: Vec<Option<String>> = TryFromSexp::try_from_sexp(sexp)?;
Ok(vec.into_iter().map(|opt| opt.map(<OsString>::from)).collect())
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
let vec: Vec<Option<String>> =
unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
Ok(vec.into_iter().map(|opt| opt.map(<OsString>::from)).collect())
}
}impl_string_wrapper_try_from_sexp!(
286 scalar: OsString;
296 option: OsString;
298 vec: OsString;
305 vec_option: OsString;
309);
310