miniextendr_api/from_r/
strings.rs1use crate::from_r::{
24 SexpError, TryFromSexp, charsxp_to_str, charsxp_to_str_unchecked, scalar_charsxp,
25 scalar_charsxp_unchecked,
26};
27use crate::{SEXP, SEXPTYPE, SexpExt};
28
29impl TryFromSexp for &'static str {
49 type Error = SexpError;
50 const CHARACTER_ONLY: bool = true;
51
52 #[inline]
53 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
54 let charsxp = scalar_charsxp(sexp)?;
55
56 if charsxp == SEXP::na_string() {
58 return Ok("");
59 }
60 if charsxp == SEXP::blank_string() {
61 return Ok("");
62 }
63
64 Ok(unsafe { charsxp_to_str(charsxp) })
66 }
67
68 unsafe fn __mx_try_from_rooted(root: crate::Root<'_>) -> Result<Self, Self::Error> {
69 let charsxp = scalar_charsxp(root.get())?;
70 if charsxp == SEXP::na_string() || charsxp == SEXP::blank_string() {
71 return Ok("");
72 }
73 let charsxp = unsafe { root.protect_child(charsxp) }.get();
74 Ok(unsafe { charsxp_to_str(charsxp) })
75 }
76
77 #[inline]
78 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
79 let charsxp = unsafe { scalar_charsxp_unchecked(sexp)? };
80
81 if charsxp == SEXP::na_string() {
83 return Ok("");
84 }
85 if charsxp == SEXP::blank_string() {
86 return Ok("");
87 }
88
89 Ok(unsafe { charsxp_to_str_unchecked(charsxp) })
91 }
92}
93
94impl TryFromSexp for Option<&'static str> {
95 type Error = SexpError;
96 const CHARACTER_ONLY: bool = true;
97
98 #[inline]
99 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
100 if sexp.type_of() == SEXPTYPE::NILSXP {
101 return Ok(None);
102 }
103
104 let charsxp = scalar_charsxp(sexp)?;
105 if charsxp == SEXP::na_string() {
106 return Ok(None);
107 }
108 if charsxp == SEXP::blank_string() {
109 return Ok(Some(""));
110 }
111
112 Ok(Some(unsafe { charsxp_to_str(charsxp) }))
113 }
114
115 unsafe fn __mx_try_from_rooted(root: crate::Root<'_>) -> Result<Self, Self::Error> {
116 if root.get().type_of() == SEXPTYPE::NILSXP {
117 return Ok(None);
118 }
119 let charsxp = scalar_charsxp(root.get())?;
120 if charsxp == SEXP::na_string() {
121 return Ok(None);
122 }
123 if charsxp == SEXP::blank_string() {
124 return Ok(Some(""));
125 }
126 let charsxp = unsafe { root.protect_child(charsxp) }.get();
127 Ok(Some(unsafe { charsxp_to_str(charsxp) }))
128 }
129
130 #[inline]
131 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
132 if sexp.type_of() == SEXPTYPE::NILSXP {
133 return Ok(None);
134 }
135
136 let charsxp = unsafe { scalar_charsxp_unchecked(sexp)? };
137 if charsxp == SEXP::na_string() {
138 return Ok(None);
139 }
140 if charsxp == SEXP::blank_string() {
141 return Ok(Some(""));
142 }
143
144 Ok(Some(unsafe { charsxp_to_str_unchecked(charsxp) }))
145 }
146}
147
148impl TryFromSexp for char {
153 type Error = SexpError;
154 const CHARACTER_ONLY: bool = true;
155
156 #[inline]
157 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
158 let s: &str = TryFromSexp::try_from_sexp(sexp)?;
159 let mut chars = s.chars();
160 match (chars.next(), chars.next()) {
161 (Some(c), None) => Ok(c),
162 (None, _) => Err(SexpError::InvalidValue(
163 "empty string cannot be converted to char".to_string(),
164 )),
165 (Some(_), Some(_)) => Err(SexpError::InvalidValue(
166 "string has more than one character".to_string(),
167 )),
168 }
169 }
170
171 #[inline]
172 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
173 let s: &str = unsafe { TryFromSexp::try_from_sexp_unchecked(sexp)? };
174 let mut chars = s.chars();
175 match (chars.next(), chars.next()) {
176 (Some(c), None) => Ok(c),
177 (None, _) => Err(SexpError::InvalidValue(
178 "empty string cannot be converted to char".to_string(),
179 )),
180 (Some(_), Some(_)) => Err(SexpError::InvalidValue(
181 "string has more than one character".to_string(),
182 )),
183 }
184 }
185}
186
187impl TryFromSexp for String {
200 type Error = SexpError;
201 const CHARACTER_ONLY: bool = true;
202
203 #[inline]
204 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
205 let charsxp = scalar_charsxp(sexp)?;
206
207 if charsxp == SEXP::na_string() {
208 return Ok(String::new());
209 }
210
211 Ok(unsafe { charsxp_to_str(charsxp) }.to_owned())
212 }
213
214 #[inline]
215 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
216 let charsxp = unsafe { scalar_charsxp_unchecked(sexp)? };
217
218 if charsxp == SEXP::na_string() {
219 return Ok(String::new());
220 }
221
222 Ok(unsafe { charsxp_to_str_unchecked(charsxp) }.to_owned())
223 }
224}
225
226impl TryFromSexp for Option<String> {
237 type Error = SexpError;
238 const CHARACTER_ONLY: bool = true;
239
240 #[inline]
241 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
242 if sexp.type_of() == SEXPTYPE::NILSXP {
244 return Ok(None);
245 }
246
247 let charsxp = scalar_charsxp(sexp)?;
248
249 if charsxp == SEXP::na_string() {
251 return Ok(None);
252 }
253
254 Ok(Some(unsafe { charsxp_to_str(charsxp) }.to_owned()))
255 }
256
257 #[inline]
258 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
259 Self::try_from_sexp(sexp)
261 }
262}
263macro_rules! impl_owned_str_from_r {
270 ($owner:ident) => {
271 impl TryFromSexp for $owner<str> {
272 type Error = SexpError;
273 const CHARACTER_ONLY: bool = true;
274 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
275 String::try_from_sexp(sexp).map(Self::from)
276 }
277 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
278 unsafe { String::try_from_sexp_unchecked(sexp) }.map(Self::from)
279 }
280 }
281 impl TryFromSexp for Option<$owner<str>> {
282 type Error = SexpError;
283 const CHARACTER_ONLY: bool = true;
284 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
285 Option::<String>::try_from_sexp(sexp).map(|v| v.map($owner::from))
286 }
287 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
288 unsafe { Option::<String>::try_from_sexp_unchecked(sexp) }
289 .map(|v| v.map($owner::from))
290 }
291 }
292 impl TryFromSexp for Vec<$owner<str>> {
293 type Error = SexpError;
294 const CHARACTER_ONLY: bool = true;
295 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
296 Vec::<String>::try_from_sexp(sexp)
297 .map(|v| v.into_iter().map($owner::from).collect())
298 }
299 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
300 unsafe { Vec::<String>::try_from_sexp_unchecked(sexp) }
301 .map(|v| v.into_iter().map($owner::from).collect())
302 }
303 }
304 impl TryFromSexp for Vec<Option<$owner<str>>> {
305 type Error = SexpError;
306 const CHARACTER_ONLY: bool = true;
307 fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
308 Vec::<Option<String>>::try_from_sexp(sexp)
309 .map(|v| v.into_iter().map(|s| s.map($owner::from)).collect())
310 }
311 unsafe fn try_from_sexp_unchecked(sexp: SEXP) -> Result<Self, Self::Error> {
312 unsafe { Vec::<Option<String>>::try_from_sexp_unchecked(sexp) }
313 .map(|v| v.into_iter().map(|s| s.map($owner::from)).collect())
314 }
315 }
316 };
317}
318use std::rc::Rc;
319use std::sync::Arc;
320impl TryFromSexp for Box<str> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
String::try_from_sexp(sexp).map(Self::from)
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
unsafe { String::try_from_sexp_unchecked(sexp) }.map(Self::from)
}
}
impl TryFromSexp for Option<Box<str>> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
Option::<String>::try_from_sexp(sexp).map(|v| v.map(Box::from))
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
unsafe {
Option::<String>::try_from_sexp_unchecked(sexp)
}.map(|v| v.map(Box::from))
}
}
impl TryFromSexp for Vec<Box<str>> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
Vec::<String>::try_from_sexp(sexp).map(|v|
v.into_iter().map(Box::from).collect())
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
unsafe {
Vec::<String>::try_from_sexp_unchecked(sexp)
}.map(|v| v.into_iter().map(Box::from).collect())
}
}
impl TryFromSexp for Vec<Option<Box<str>>> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
Vec::<Option<String>>::try_from_sexp(sexp).map(|v|
v.into_iter().map(|s| s.map(Box::from)).collect())
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
unsafe {
Vec::<Option<String>>::try_from_sexp_unchecked(sexp)
}.map(|v| v.into_iter().map(|s| s.map(Box::from)).collect())
}
}impl_owned_str_from_r!(Box);
321impl TryFromSexp for Rc<str> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
String::try_from_sexp(sexp).map(Self::from)
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
unsafe { String::try_from_sexp_unchecked(sexp) }.map(Self::from)
}
}
impl TryFromSexp for Option<Rc<str>> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
Option::<String>::try_from_sexp(sexp).map(|v| v.map(Rc::from))
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
unsafe {
Option::<String>::try_from_sexp_unchecked(sexp)
}.map(|v| v.map(Rc::from))
}
}
impl TryFromSexp for Vec<Rc<str>> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
Vec::<String>::try_from_sexp(sexp).map(|v|
v.into_iter().map(Rc::from).collect())
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
unsafe {
Vec::<String>::try_from_sexp_unchecked(sexp)
}.map(|v| v.into_iter().map(Rc::from).collect())
}
}
impl TryFromSexp for Vec<Option<Rc<str>>> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
Vec::<Option<String>>::try_from_sexp(sexp).map(|v|
v.into_iter().map(|s| s.map(Rc::from)).collect())
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
unsafe {
Vec::<Option<String>>::try_from_sexp_unchecked(sexp)
}.map(|v| v.into_iter().map(|s| s.map(Rc::from)).collect())
}
}impl_owned_str_from_r!(Rc);
322impl TryFromSexp for Arc<str> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
String::try_from_sexp(sexp).map(Self::from)
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
unsafe { String::try_from_sexp_unchecked(sexp) }.map(Self::from)
}
}
impl TryFromSexp for Option<Arc<str>> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
Option::<String>::try_from_sexp(sexp).map(|v| v.map(Arc::from))
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
unsafe {
Option::<String>::try_from_sexp_unchecked(sexp)
}.map(|v| v.map(Arc::from))
}
}
impl TryFromSexp for Vec<Arc<str>> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
Vec::<String>::try_from_sexp(sexp).map(|v|
v.into_iter().map(Arc::from).collect())
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
unsafe {
Vec::<String>::try_from_sexp_unchecked(sexp)
}.map(|v| v.into_iter().map(Arc::from).collect())
}
}
impl TryFromSexp for Vec<Option<Arc<str>>> {
type Error = SexpError;
const CHARACTER_ONLY: bool = true;
fn try_from_sexp(sexp: SEXP) -> Result<Self, Self::Error> {
Vec::<Option<String>>::try_from_sexp(sexp).map(|v|
v.into_iter().map(|s| s.map(Arc::from)).collect())
}
unsafe fn try_from_sexp_unchecked(sexp: SEXP)
-> Result<Self, Self::Error> {
unsafe {
Vec::<Option<String>>::try_from_sexp_unchecked(sexp)
}.map(|v| v.into_iter().map(|s| s.map(Arc::from)).collect())
}
}impl_owned_str_from_r!(Arc);
323