1use super::*;
2use crate::scalar::Scalar;
3use crate::single_threaded;
4use extendr_ffi::{
5 cetype_t, R_BlankString, R_NaInt, R_NaReal, R_NaString, R_NilValue, Rcomplex, Rf_mkCharLenCE,
6 COMPLEX, INTEGER, LOGICAL, RAW, REAL, SET_STRING_ELT, SEXPTYPE,
7};
8mod repeat_into_robj;
9
10pub(crate) fn str_to_character(s: &str) -> SEXP {
17 unsafe {
18 if s.is_na() {
19 R_NaString
20 } else if s.is_empty() {
21 R_BlankString
22 } else {
23 single_threaded(|| {
24 Rf_mkCharLenCE(s.as_ptr().cast(), s.len() as i32, cetype_t::CE_UTF8)
26 })
27 }
28 }
29}
30
31impl From<()> for Robj {
33 fn from(_: ()) -> Self {
34 unsafe { Robj::from_sexp(R_NilValue) }
36 }
37}
38
39#[cfg(not(any(feature = "result_list", feature = "result_condition")))]
68impl<T, E> From<std::result::Result<T, E>> for Robj
69where
70 T: Into<Robj>,
71 E: std::fmt::Debug,
72{
73 fn from(res: std::result::Result<T, E>) -> Self {
74 res.unwrap().into()
75 }
76}
77
78#[cfg(all(feature = "result_condition", not(feature = "result_list")))]
85impl<T, E> From<std::result::Result<T, E>> for Robj
86where
87 T: Into<Robj>,
88 E: Into<Robj>,
89{
90 fn from(res: std::result::Result<T, E>) -> Self {
91 use crate as extendr_api;
92 match res {
93 Ok(x) => x.into(),
94 Err(x) => {
95 let mut err = list!(message = "extendr_err", value = x.into());
96 err.set_class(["extendr_error", "error", "condition"])
97 .expect("internal error: failed to set class");
98 err.into()
99 }
100 }
101 }
102}
103
104#[cfg(feature = "result_list")]
111impl<T, E> From<std::result::Result<T, E>> for Robj
112where
113 T: Into<Robj>,
114 E: Into<Robj>,
115{
116 fn from(res: std::result::Result<T, E>) -> Self {
117 use crate as extendr_api;
118 let mut result = match res {
119 Ok(x) => list!(ok = x.into(), err = NULL),
120 Err(x) => {
121 let err_robj = x.into();
122 if err_robj.is_null() {
123 panic!("Internal error: result_list not allowed to return NULL as err-value")
124 }
125 list!(ok = NULL, err = err_robj)
126 }
127 };
128 result
129 .set_class(&["extendr_result"])
130 .expect("Internal error: failed to set class");
131 result.into()
132 }
133}
134
135impl From<Error> for Robj {
137 fn from(res: Error) -> Self {
138 res.to_string().into()
139 }
140}
141impl From<Error> for String {
142 fn from(res: Error) -> Self {
143 res.to_string()
144 }
145}
146
147impl From<&Robj> for Robj {
149 fn from(val: &Robj) -> Self {
152 unsafe { Robj::from_sexp(val.get()) }
153 }
154}
155
156pub trait IntoRobj {
161 fn into_robj(self) -> Robj;
162}
163
164impl<T> IntoRobj for T
165where
166 Robj: From<T>,
167{
168 fn into_robj(self) -> Robj {
169 self.into()
170 }
171}
172
173pub trait ToVectorValue {
177 fn sexptype() -> SEXPTYPE {
178 SEXPTYPE::NILSXP
179 }
180
181 fn to_real(&self) -> f64
182 where
183 Self: Sized,
184 {
185 0.
186 }
187
188 fn to_complex(&self) -> Rcomplex
189 where
190 Self: Sized,
191 {
192 Rcomplex { r: 0., i: 0. }
193 }
194
195 fn to_integer(&self) -> i32
196 where
197 Self: Sized,
198 {
199 std::i32::MIN
200 }
201
202 fn to_logical(&self) -> i32
203 where
204 Self: Sized,
205 {
206 std::i32::MIN
207 }
208
209 fn to_raw(&self) -> u8
210 where
211 Self: Sized,
212 {
213 0
214 }
215
216 fn to_sexp(&self) -> SEXP
217 where
218 Self: Sized,
219 {
220 unsafe { R_NilValue }
221 }
222}
223
224macro_rules! impl_real_tvv {
225 ($t: ty) => {
226 impl ToVectorValue for $t {
227 fn sexptype() -> SEXPTYPE {
228 SEXPTYPE::REALSXP
229 }
230
231 fn to_real(&self) -> f64 {
232 *self as f64
233 }
234 }
235
236 impl ToVectorValue for &$t {
237 fn sexptype() -> SEXPTYPE {
238 SEXPTYPE::REALSXP
239 }
240
241 fn to_real(&self) -> f64 {
242 **self as f64
243 }
244 }
245
246 impl ToVectorValue for Option<$t> {
247 fn sexptype() -> SEXPTYPE {
248 SEXPTYPE::REALSXP
249 }
250
251 fn to_real(&self) -> f64 {
252 if self.is_some() {
253 self.unwrap() as f64
254 } else {
255 unsafe { R_NaReal }
256 }
257 }
258 }
259 };
260}
261
262impl_real_tvv!(f64);
263impl_real_tvv!(f32);
264
265impl_real_tvv!(i64);
268impl_real_tvv!(u32);
269impl_real_tvv!(u64);
270impl_real_tvv!(usize);
271
272macro_rules! impl_complex_tvv {
273 ($t: ty) => {
274 impl ToVectorValue for $t {
275 fn sexptype() -> SEXPTYPE {
276 SEXPTYPE::CPLXSXP
277 }
278
279 fn to_complex(&self) -> Rcomplex {
280 unsafe { std::mem::transmute(*self) }
281 }
282 }
283
284 impl ToVectorValue for &$t {
285 fn sexptype() -> SEXPTYPE {
286 SEXPTYPE::CPLXSXP
287 }
288
289 fn to_complex(&self) -> Rcomplex {
290 unsafe { std::mem::transmute(**self) }
291 }
292 }
293 };
294}
295
296impl_complex_tvv!(c64);
297impl_complex_tvv!(Rcplx);
298impl_complex_tvv!((f64, f64));
299
300macro_rules! impl_integer_tvv {
301 ($t: ty) => {
302 impl ToVectorValue for $t {
303 fn sexptype() -> SEXPTYPE {
304 SEXPTYPE::INTSXP
305 }
306
307 fn to_integer(&self) -> i32 {
308 *self as i32
309 }
310 }
311
312 impl ToVectorValue for &$t {
313 fn sexptype() -> SEXPTYPE {
314 SEXPTYPE::INTSXP
315 }
316
317 fn to_integer(&self) -> i32 {
318 **self as i32
319 }
320 }
321
322 impl ToVectorValue for Option<$t> {
323 fn sexptype() -> SEXPTYPE {
324 SEXPTYPE::INTSXP
325 }
326
327 fn to_integer(&self) -> i32 {
328 if self.is_some() {
329 self.unwrap() as i32
330 } else {
331 unsafe { R_NaInt }
332 }
333 }
334 }
335 };
336}
337
338impl_integer_tvv!(i8);
339impl_integer_tvv!(i16);
340impl_integer_tvv!(i32);
341impl_integer_tvv!(u16);
342
343impl ToVectorValue for u8 {
344 fn sexptype() -> SEXPTYPE {
345 SEXPTYPE::RAWSXP
346 }
347
348 fn to_raw(&self) -> u8 {
349 *self
350 }
351}
352
353impl ToVectorValue for &u8 {
354 fn sexptype() -> SEXPTYPE {
355 SEXPTYPE::RAWSXP
356 }
357
358 fn to_raw(&self) -> u8 {
359 **self
360 }
361}
362
363macro_rules! impl_str_tvv {
364 ($t: ty) => {
365 impl ToVectorValue for $t {
366 fn sexptype() -> SEXPTYPE {
367 SEXPTYPE::STRSXP
368 }
369
370 fn to_sexp(&self) -> SEXP
371 where
372 Self: Sized,
373 {
374 str_to_character(self.as_ref())
375 }
376 }
377
378 impl ToVectorValue for &$t {
379 fn sexptype() -> SEXPTYPE {
380 SEXPTYPE::STRSXP
381 }
382
383 fn to_sexp(&self) -> SEXP
384 where
385 Self: Sized,
386 {
387 str_to_character(self.as_ref())
388 }
389 }
390
391 impl ToVectorValue for Option<$t> {
392 fn sexptype() -> SEXPTYPE {
393 SEXPTYPE::STRSXP
394 }
395
396 fn to_sexp(&self) -> SEXP
397 where
398 Self: Sized,
399 {
400 if let Some(s) = self {
401 str_to_character(s.as_ref())
402 } else {
403 unsafe { R_NaString }
404 }
405 }
406 }
407 };
408}
409
410impl_str_tvv! {&str}
411impl_str_tvv! {String}
412
413impl ToVectorValue for bool {
414 fn sexptype() -> SEXPTYPE {
415 SEXPTYPE::LGLSXP
416 }
417
418 fn to_logical(&self) -> i32
419 where
420 Self: Sized,
421 {
422 *self as i32
423 }
424}
425
426impl ToVectorValue for &bool {
427 fn sexptype() -> SEXPTYPE {
428 SEXPTYPE::LGLSXP
429 }
430
431 fn to_logical(&self) -> i32
432 where
433 Self: Sized,
434 {
435 **self as i32
436 }
437}
438
439impl ToVectorValue for Rbool {
440 fn sexptype() -> SEXPTYPE {
441 SEXPTYPE::LGLSXP
442 }
443
444 fn to_logical(&self) -> i32
445 where
446 Self: Sized,
447 {
448 self.inner()
449 }
450}
451
452impl ToVectorValue for &Rbool {
453 fn sexptype() -> SEXPTYPE {
454 SEXPTYPE::LGLSXP
455 }
456
457 fn to_logical(&self) -> i32
458 where
459 Self: Sized,
460 {
461 self.inner()
462 }
463}
464
465impl ToVectorValue for Option<bool> {
466 fn sexptype() -> SEXPTYPE {
467 SEXPTYPE::LGLSXP
468 }
469
470 fn to_logical(&self) -> i32 {
471 if self.is_some() {
472 self.unwrap() as i32
473 } else {
474 unsafe { R_NaInt }
475 }
476 }
477}
478
479fn fixed_size_collect<I>(iter: I, len: usize) -> Robj
481where
482 I: Iterator,
483 I: Sized,
484 I::Item: ToVectorValue,
485{
486 single_threaded(|| unsafe {
487 let sexptype = I::Item::sexptype();
489 if sexptype != SEXPTYPE::NILSXP {
490 let res = Robj::alloc_vector(sexptype, len);
491 let sexp = res.get();
492 match sexptype {
493 SEXPTYPE::REALSXP => {
494 let ptr = REAL(sexp);
495 for (i, v) in iter.enumerate() {
496 *ptr.add(i) = v.to_real();
497 }
498 }
499 SEXPTYPE::CPLXSXP => {
500 let ptr = COMPLEX(sexp);
501 for (i, v) in iter.enumerate() {
502 *ptr.add(i) = v.to_complex();
503 }
504 }
505 SEXPTYPE::INTSXP => {
506 let ptr = INTEGER(sexp);
507 for (i, v) in iter.enumerate() {
508 *ptr.add(i) = v.to_integer();
509 }
510 }
511 SEXPTYPE::LGLSXP => {
512 let ptr = LOGICAL(sexp);
513 for (i, v) in iter.enumerate() {
514 *ptr.add(i) = v.to_logical();
515 }
516 }
517 SEXPTYPE::STRSXP => {
518 for (i, v) in iter.enumerate() {
519 SET_STRING_ELT(sexp, i as isize, v.to_sexp());
520 }
521 }
522 SEXPTYPE::RAWSXP => {
523 let ptr = RAW(sexp);
524 for (i, v) in iter.enumerate() {
525 *ptr.add(i) = v.to_raw();
526 }
527 }
528 _ => {
529 panic!("unexpected SEXPTYPE in collect_robj");
530 }
531 }
532 res
533 } else {
534 Robj::from(())
535 }
536 })
537}
538
539pub trait RobjItertools: Iterator {
541 fn collect_robj(self) -> Robj
564 where
565 Self: Iterator,
566 Self: Sized,
567 Self::Item: ToVectorValue,
568 {
569 if let (len, Some(max)) = self.size_hint() {
570 if len == max {
571 return fixed_size_collect(self, len);
572 }
573 }
574 let vec: Vec<_> = self.collect();
576 assert!(vec.iter().size_hint() == (vec.len(), Some(vec.len())));
577 vec.into_iter().collect_robj()
578 }
579
580 fn collect_rarray<const LEN: usize>(
587 self,
588 dims: [usize; LEN],
589 ) -> Result<RArray<Self::Item, [usize; LEN]>>
590 where
591 Self: Iterator,
592 Self: Sized,
593 Self::Item: ToVectorValue,
594 Robj: for<'a> AsTypedSlice<'a, Self::Item>,
595 {
596 let mut vector = self.collect_robj();
597 let prod = dims.iter().product::<usize>();
598 if prod != vector.len() {
599 return Err(Error::Other(format!(
600 "The vector length ({}) does not match the length implied by the dimensions ({})",
601 vector.len(),
602 prod
603 )));
604 }
605 vector.set_attrib(wrapper::symbol::dim_symbol(), dims.iter().collect_robj())?;
606 let _data = vector.as_typed_slice().ok_or(Error::Other(
607 "Unknown error in converting to slice".to_string(),
608 ))?;
609 Ok(RArray::from_parts(vector, dims))
610 }
611}
612
613impl<T> RobjItertools for T where T: Iterator {}
615
616impl<T> From<T> for Robj
618where
619 T: ToVectorValue,
620{
621 fn from(scalar: T) -> Self {
622 Some(scalar).into_iter().collect_robj()
623 }
624}
625
626macro_rules! impl_from_as_iterator {
627 ($t: ty) => {
628 impl<T> From<$t> for Robj
629 where
630 $t: RobjItertools,
631 <$t as Iterator>::Item: ToVectorValue,
632 T: ToVectorValue,
633 {
634 fn from(val: $t) -> Self {
635 val.collect_robj()
636 }
637 }
638 };
639}
640
641impl<'a, T, const N: usize> From<[T; N]> for Robj
653where
654 Self: 'a,
655 T: ToVectorValue,
656{
657 fn from(val: [T; N]) -> Self {
658 fixed_size_collect(val.into_iter(), N)
659 }
660}
661
662impl<'a, T, const N: usize> From<&'a [T; N]> for Robj
663where
664 Self: 'a,
665 &'a T: ToVectorValue + 'a,
666{
667 fn from(val: &'a [T; N]) -> Self {
668 fixed_size_collect(val.iter(), N)
669 }
670}
671
672impl<'a, T, const N: usize> From<&'a mut [T; N]> for Robj
673where
674 Self: 'a,
675 &'a mut T: ToVectorValue + 'a,
676{
677 fn from(val: &'a mut [T; N]) -> Self {
678 fixed_size_collect(val.iter_mut(), N)
679 }
680}
681
682impl<T: ToVectorValue + Clone> From<&Vec<T>> for Robj {
683 fn from(value: &Vec<T>) -> Self {
684 let len = value.len();
685 fixed_size_collect(value.iter().cloned(), len)
686 }
687}
688
689impl<T: ToVectorValue> From<Vec<T>> for Robj {
690 fn from(value: Vec<T>) -> Self {
691 let len = value.len();
692 fixed_size_collect(value.into_iter(), len)
693 }
694}
695
696impl<'a, T> From<&'a [T]> for Robj
697where
698 Self: 'a,
699 T: 'a,
700 &'a T: ToVectorValue,
701{
702 fn from(val: &'a [T]) -> Self {
703 val.iter().collect_robj()
704 }
705}
706
707impl_from_as_iterator! {Range<T>}
708impl_from_as_iterator! {RangeInclusive<T>}
709
710impl From<Vec<Robj>> for Robj {
711 fn from(val: Vec<Robj>) -> Self {
713 List::from_values(val.iter()).into()
714 }
715}
716
717impl From<Vec<Rstr>> for Robj {
718 fn from(val: Vec<Rstr>) -> Self {
720 Strings::from_values(val).into()
721 }
722}
723
724#[cfg(test)]
725mod test {
726 use super::*;
727 use crate as extendr_api;
728
729 #[test]
730 fn test_vec_rint_to_robj() {
731 test! {
732 let int_vec = vec![3,4,0,-2];
733 let int_vec_robj: Robj = int_vec.clone().into();
734 assert_eq!(int_vec_robj.as_integer_slice().unwrap(), &int_vec);
736
737 let rint_vec = vec![Rint::new(3), Rint::new(4), Rint::new(0), Rint::new(-2)];
738 let rint_vec_robj: Robj = rint_vec.into();
739 assert_eq!(rint_vec_robj.as_integer_slice().unwrap(), &int_vec);
741 }
742 }
743
744 #[test]
745 fn test_collect_rarray_matrix() {
746 test! {
747 let rmat = (1i32..=16).collect_rarray([4, 4]);
749 assert!(rmat.is_ok());
750 assert_eq!(Robj::from(rmat), R!("matrix(1:16, nrow=4)").unwrap());
751 }
752 }
753
754 #[test]
755 fn test_collect_rarray_tensor() {
756 test! {
757 let rmat = (1i32..=16).collect_rarray([2, 4, 2]);
759 assert!(rmat.is_ok());
760 assert_eq!(Robj::from(rmat), R!("array(1:16, dim=c(2, 4, 2))").unwrap());
761 }
762 }
763
764 #[test]
765 fn test_collect_rarray_matrix_failure() {
766 test! {
767 let rmat = (1i32..=16).collect_rarray([3, 3]);
769 assert!(rmat.is_err());
770 let msg = rmat.unwrap_err().to_string();
771 assert!(msg.contains('9'));
772 assert!(msg.contains("dimension"));
773 }
774 }
775
776 #[test]
777 fn test_collect_tensor_failure() {
778 test! {
779 let rmat = (1i32..=16).collect_rarray([3, 3, 3]);
781 assert!(rmat.is_err());
782 let msg = rmat.unwrap_err().to_string();
783 assert!(msg.contains("27"));
784 assert!(msg.contains("dimension"));
785 }
786 }
787
788 #[test]
789 #[cfg(all(feature = "result_condition", not(feature = "result_list")))]
790 fn test_result_condition() {
791 use crate::prelude::*;
792 fn my_err_f() -> std::result::Result<f64, f64> {
793 Err(42.0) }
795
796 test! {
797 assert_eq!(
798 r!(my_err_f()),
799 R!(
800 "structure(list(message = 'extendr_err',
801 value = 42.0), class = c('extendr_error', 'error', 'condition'))"
802 ).unwrap()
803 );
804 }
805 }
806
807 #[test]
808 #[cfg(feature = "result_list")]
809 fn test_result_list() {
810 use crate::prelude::*;
811 fn my_err_f() -> std::result::Result<f64, String> {
812 Err("We have water in the engine room!".to_string())
813 }
814
815 fn my_ok_f() -> std::result::Result<f64, String> {
816 Ok(123.123)
817 }
818
819 test! {
820 assert_eq!(
821 r!(my_err_f()),
822 R!("x=list(ok=NULL, err='We have water in the engine room!')
823 class(x)='extendr_result'
824 x"
825 ).unwrap()
826 );
827 assert_eq!(
828 r!(my_ok_f()),
829 R!("x = list(ok=123.123, err=NULL)
830 class(x)='extendr_result'
831 x"
832 ).unwrap()
833 );
834 }
835 }
836}