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")))]
66impl<T, E> From<std::result::Result<T, E>> for Robj
67where
68 T: Into<Robj>,
69 E: std::fmt::Debug + std::fmt::Display,
70{
71 fn from(res: std::result::Result<T, E>) -> Self {
72 match res {
73 Ok(val) => val.into(),
74 Err(err) => panic!("{}", err),
75 }
76 }
77}
78
79#[cfg(all(feature = "result_condition", not(feature = "result_list")))]
86impl<T, E> From<std::result::Result<T, E>> for Robj
87where
88 T: Into<Robj>,
89 E: Into<Robj>,
90{
91 fn from(res: std::result::Result<T, E>) -> Self {
92 use crate as extendr_api;
93 match res {
94 Ok(x) => x.into(),
95 Err(x) => {
96 let mut err = list!(message = "extendr_err", value = x.into());
97 err.set_class(["extendr_error", "error", "condition"])
98 .expect("internal error: failed to set class");
99 err.into()
100 }
101 }
102 }
103}
104
105#[cfg(feature = "result_list")]
112impl<T, E> From<std::result::Result<T, E>> for Robj
113where
114 T: Into<Robj>,
115 E: Into<Robj>,
116{
117 fn from(res: std::result::Result<T, E>) -> Self {
118 use crate as extendr_api;
119 let mut result = match res {
120 Ok(x) => list!(ok = x.into(), err = NULL),
121 Err(x) => {
122 let err_robj = x.into();
123 if err_robj.is_null() {
124 panic!("Internal error: result_list not allowed to return NULL as err-value")
125 }
126 list!(ok = NULL, err = err_robj)
127 }
128 };
129 result
130 .set_class(&["extendr_result"])
131 .expect("Internal error: failed to set class");
132 result.into()
133 }
134}
135
136impl From<Error> for Robj {
138 fn from(res: Error) -> Self {
139 res.to_string().into()
140 }
141}
142impl From<Error> for String {
143 fn from(res: Error) -> Self {
144 res.to_string()
145 }
146}
147
148impl From<&Robj> for Robj {
150 fn from(val: &Robj) -> Self {
153 unsafe { Robj::from_sexp(val.get()) }
154 }
155}
156
157pub trait IntoRobj {
162 fn into_robj(self) -> Robj;
163}
164
165impl<T> IntoRobj for T
166where
167 Robj: From<T>,
168{
169 fn into_robj(self) -> Robj {
170 self.into()
171 }
172}
173
174pub trait ToVectorValue {
178 fn sexptype() -> SEXPTYPE {
179 SEXPTYPE::NILSXP
180 }
181
182 fn to_real(&self) -> f64
183 where
184 Self: Sized,
185 {
186 0.
187 }
188
189 fn to_complex(&self) -> Rcomplex
190 where
191 Self: Sized,
192 {
193 Rcomplex { r: 0., i: 0. }
194 }
195
196 fn to_integer(&self) -> i32
197 where
198 Self: Sized,
199 {
200 i32::MIN
201 }
202
203 fn to_logical(&self) -> i32
204 where
205 Self: Sized,
206 {
207 i32::MIN
208 }
209
210 fn to_raw(&self) -> u8
211 where
212 Self: Sized,
213 {
214 0
215 }
216
217 fn to_sexp(&self) -> SEXP
218 where
219 Self: Sized,
220 {
221 unsafe { R_NilValue }
222 }
223}
224
225macro_rules! impl_real_tvv {
226 ($t: ty) => {
227 impl ToVectorValue for $t {
228 fn sexptype() -> SEXPTYPE {
229 SEXPTYPE::REALSXP
230 }
231
232 fn to_real(&self) -> f64 {
233 *self as f64
234 }
235 }
236
237 impl ToVectorValue for &$t {
238 fn sexptype() -> SEXPTYPE {
239 SEXPTYPE::REALSXP
240 }
241
242 fn to_real(&self) -> f64 {
243 **self as f64
244 }
245 }
246
247 impl ToVectorValue for Option<$t> {
248 fn sexptype() -> SEXPTYPE {
249 SEXPTYPE::REALSXP
250 }
251
252 fn to_real(&self) -> f64 {
253 if self.is_some() {
254 self.unwrap() as f64
255 } else {
256 unsafe { R_NaReal }
257 }
258 }
259 }
260 };
261}
262
263impl_real_tvv!(f64);
264impl_real_tvv!(f32);
265
266impl_real_tvv!(i64);
269impl_real_tvv!(u32);
270impl_real_tvv!(u64);
271impl_real_tvv!(usize);
272
273macro_rules! impl_complex_tvv {
274 ($t: ty) => {
275 impl ToVectorValue for $t {
276 fn sexptype() -> SEXPTYPE {
277 SEXPTYPE::CPLXSXP
278 }
279
280 fn to_complex(&self) -> Rcomplex {
281 unsafe { std::mem::transmute(*self) }
282 }
283 }
284
285 impl ToVectorValue for &$t {
286 fn sexptype() -> SEXPTYPE {
287 SEXPTYPE::CPLXSXP
288 }
289
290 fn to_complex(&self) -> Rcomplex {
291 unsafe { std::mem::transmute(**self) }
292 }
293 }
294 };
295}
296
297impl_complex_tvv!(c64);
298impl_complex_tvv!(Rcplx);
299impl_complex_tvv!((f64, f64));
300
301macro_rules! impl_integer_tvv {
302 ($t: ty) => {
303 impl ToVectorValue for $t {
304 fn sexptype() -> SEXPTYPE {
305 SEXPTYPE::INTSXP
306 }
307
308 fn to_integer(&self) -> i32 {
309 *self as i32
310 }
311 }
312
313 impl ToVectorValue for &$t {
314 fn sexptype() -> SEXPTYPE {
315 SEXPTYPE::INTSXP
316 }
317
318 fn to_integer(&self) -> i32 {
319 **self as i32
320 }
321 }
322
323 impl ToVectorValue for Option<$t> {
324 fn sexptype() -> SEXPTYPE {
325 SEXPTYPE::INTSXP
326 }
327
328 fn to_integer(&self) -> i32 {
329 if self.is_some() {
330 self.unwrap() as i32
331 } else {
332 unsafe { R_NaInt }
333 }
334 }
335 }
336 };
337}
338
339impl_integer_tvv!(i8);
340impl_integer_tvv!(i16);
341impl_integer_tvv!(i32);
342impl_integer_tvv!(u16);
343
344impl ToVectorValue for u8 {
345 fn sexptype() -> SEXPTYPE {
346 SEXPTYPE::RAWSXP
347 }
348
349 fn to_raw(&self) -> u8 {
350 *self
351 }
352}
353
354impl ToVectorValue for &u8 {
355 fn sexptype() -> SEXPTYPE {
356 SEXPTYPE::RAWSXP
357 }
358
359 fn to_raw(&self) -> u8 {
360 **self
361 }
362}
363
364macro_rules! impl_str_tvv {
365 ($t: ty) => {
366 impl ToVectorValue for $t {
367 fn sexptype() -> SEXPTYPE {
368 SEXPTYPE::STRSXP
369 }
370
371 fn to_sexp(&self) -> SEXP
372 where
373 Self: Sized,
374 {
375 str_to_character(self.as_ref())
376 }
377 }
378
379 impl ToVectorValue for &$t {
380 fn sexptype() -> SEXPTYPE {
381 SEXPTYPE::STRSXP
382 }
383
384 fn to_sexp(&self) -> SEXP
385 where
386 Self: Sized,
387 {
388 str_to_character(self.as_ref())
389 }
390 }
391
392 impl ToVectorValue for Option<$t> {
393 fn sexptype() -> SEXPTYPE {
394 SEXPTYPE::STRSXP
395 }
396
397 fn to_sexp(&self) -> SEXP
398 where
399 Self: Sized,
400 {
401 if let Some(s) = self {
402 str_to_character(s.as_ref())
403 } else {
404 unsafe { R_NaString }
405 }
406 }
407 }
408 };
409}
410
411impl_str_tvv! {&str}
412impl_str_tvv! {String}
413
414impl ToVectorValue for bool {
415 fn sexptype() -> SEXPTYPE {
416 SEXPTYPE::LGLSXP
417 }
418
419 fn to_logical(&self) -> i32
420 where
421 Self: Sized,
422 {
423 *self as i32
424 }
425}
426
427impl ToVectorValue for &bool {
428 fn sexptype() -> SEXPTYPE {
429 SEXPTYPE::LGLSXP
430 }
431
432 fn to_logical(&self) -> i32
433 where
434 Self: Sized,
435 {
436 **self as i32
437 }
438}
439
440impl ToVectorValue for Rbool {
441 fn sexptype() -> SEXPTYPE {
442 SEXPTYPE::LGLSXP
443 }
444
445 fn to_logical(&self) -> i32
446 where
447 Self: Sized,
448 {
449 self.inner()
450 }
451}
452
453impl ToVectorValue for &Rbool {
454 fn sexptype() -> SEXPTYPE {
455 SEXPTYPE::LGLSXP
456 }
457
458 fn to_logical(&self) -> i32
459 where
460 Self: Sized,
461 {
462 self.inner()
463 }
464}
465
466impl ToVectorValue for Option<bool> {
467 fn sexptype() -> SEXPTYPE {
468 SEXPTYPE::LGLSXP
469 }
470
471 fn to_logical(&self) -> i32 {
472 if self.is_some() {
473 self.unwrap() as i32
474 } else {
475 unsafe { R_NaInt }
476 }
477 }
478}
479
480fn fixed_size_collect<I>(iter: I, len: usize) -> Robj
482where
483 I: Iterator,
484 I: Sized,
485 I::Item: ToVectorValue,
486{
487 single_threaded(|| unsafe {
488 let sexptype = I::Item::sexptype();
490 if sexptype != SEXPTYPE::NILSXP {
491 let res = Robj::alloc_vector(sexptype, len);
492 let sexp = res.get();
493 match sexptype {
494 SEXPTYPE::REALSXP => {
495 let ptr = REAL(sexp);
496 for (i, v) in iter.enumerate() {
497 *ptr.add(i) = v.to_real();
498 }
499 }
500 SEXPTYPE::CPLXSXP => {
501 let ptr = COMPLEX(sexp);
502 for (i, v) in iter.enumerate() {
503 *ptr.add(i) = v.to_complex();
504 }
505 }
506 SEXPTYPE::INTSXP => {
507 let ptr = INTEGER(sexp);
508 for (i, v) in iter.enumerate() {
509 *ptr.add(i) = v.to_integer();
510 }
511 }
512 SEXPTYPE::LGLSXP => {
513 let ptr = LOGICAL(sexp);
514 for (i, v) in iter.enumerate() {
515 *ptr.add(i) = v.to_logical();
516 }
517 }
518 SEXPTYPE::STRSXP => {
519 for (i, v) in iter.enumerate() {
520 SET_STRING_ELT(sexp, i as isize, v.to_sexp());
521 }
522 }
523 SEXPTYPE::RAWSXP => {
524 let ptr = RAW(sexp);
525 for (i, v) in iter.enumerate() {
526 *ptr.add(i) = v.to_raw();
527 }
528 }
529 _ => {
530 panic!("unexpected SEXPTYPE in collect_robj");
531 }
532 }
533 res
534 } else {
535 Robj::from(())
536 }
537 })
538}
539
540pub trait RobjItertools: Iterator {
542 fn collect_robj(self) -> Robj
565 where
566 Self: Iterator,
567 Self: Sized,
568 Self::Item: ToVectorValue,
569 {
570 if let (len, Some(max)) = self.size_hint() {
571 if len == max {
572 return fixed_size_collect(self, len);
573 }
574 }
575 let vec: Vec<_> = self.collect();
577 assert!(vec.iter().size_hint() == (vec.len(), Some(vec.len())));
578 vec.into_iter().collect_robj()
579 }
580
581 fn collect_rarray<const LEN: usize>(
588 self,
589 dims: [usize; LEN],
590 ) -> Result<RArray<Self::Item, [usize; LEN]>>
591 where
592 Self: Iterator,
593 Self: Sized,
594 Self::Item: ToVectorValue,
595 Robj: for<'a> AsTypedSlice<'a, Self::Item>,
596 {
597 let mut vector = self.collect_robj();
598 let prod = dims.iter().product::<usize>();
599 if prod != vector.len() {
600 return Err(Error::Other(format!(
601 "The vector length ({}) does not match the length implied by the dimensions ({})",
602 vector.len(),
603 prod
604 )));
605 }
606 vector.set_attrib(wrapper::symbol::dim_symbol(), dims.iter().collect_robj())?;
607 let _data = vector.as_typed_slice().ok_or(Error::Other(
608 "Unknown error in converting to slice".to_string(),
609 ))?;
610 Ok(RArray::from_parts(vector, dims))
611 }
612}
613
614impl<T> RobjItertools for T where T: Iterator {}
616
617impl<T> From<T> for Robj
619where
620 T: ToVectorValue,
621{
622 fn from(scalar: T) -> Self {
623 Some(scalar).into_iter().collect_robj()
624 }
625}
626
627macro_rules! impl_from_as_iterator {
628 ($t: ty) => {
629 impl<T> From<$t> for Robj
630 where
631 $t: RobjItertools,
632 <$t as Iterator>::Item: ToVectorValue,
633 T: ToVectorValue,
634 {
635 fn from(val: $t) -> Self {
636 val.collect_robj()
637 }
638 }
639 };
640}
641
642impl<T, const N: usize> From<[T; N]> for Robj
654where
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}