1use super::*;
2use crate::single_threaded;
3use extendr_ffi::{
4 cetype_t, R_BlankString, R_NaInt, R_NaReal, R_NaString, R_NilValue, Rcomplex, Rf_mkCharLenCE,
5 COMPLEX, INTEGER, LOGICAL, RAW, REAL, SET_STRING_ELT, SEXPTYPE,
6};
7mod repeat_into_robj;
8
9pub(crate) fn str_to_character(s: &str) -> SEXP {
16 unsafe {
17 if s.is_na() {
18 R_NaString
19 } else if s.is_empty() {
20 R_BlankString
21 } else {
22 single_threaded(|| {
23 Rf_mkCharLenCE(s.as_ptr().cast(), s.len() as i32, cetype_t::CE_UTF8)
25 })
26 }
27 }
28}
29
30impl From<()> for Robj {
32 fn from(_: ()) -> Self {
33 unsafe { Robj::from_sexp(R_NilValue) }
35 }
36}
37
38#[cfg(not(any(feature = "result_list", feature = "result_condition")))]
65impl<T, E> From<std::result::Result<T, E>> for Robj
66where
67 T: Into<Robj>,
68 E: std::fmt::Debug + std::fmt::Display,
69{
70 fn from(res: std::result::Result<T, E>) -> Self {
71 res.unwrap().into()
72 }
73}
74
75#[cfg(all(feature = "result_condition", not(feature = "result_list")))]
82impl<T, E> From<std::result::Result<T, E>> for Robj
83where
84 T: Into<Robj>,
85 E: Into<Robj>,
86{
87 fn from(res: std::result::Result<T, E>) -> Self {
88 use crate as extendr_api;
89 match res {
90 Ok(x) => x.into(),
91 Err(x) => {
92 let mut err = list!(message = "extendr_err", value = x.into());
93 err.set_class(["extendr_error", "error", "condition"])
94 .expect("internal error: failed to set class");
95 err.into()
96 }
97 }
98 }
99}
100
101#[cfg(feature = "result_list")]
108impl<T, E> From<std::result::Result<T, E>> for Robj
109where
110 T: Into<Robj>,
111 E: Into<Robj>,
112{
113 fn from(res: std::result::Result<T, E>) -> Self {
114 use crate as extendr_api;
115 let mut result = match res {
116 Ok(x) => list!(ok = x.into(), err = NULL),
117 Err(x) => {
118 let err_robj = x.into();
119 if err_robj.is_null() {
120 panic!("Internal error: result_list not allowed to return NULL as err-value")
121 }
122 list!(ok = NULL, err = err_robj)
123 }
124 };
125 result
126 .set_class(&["extendr_result"])
127 .expect("Internal error: failed to set class");
128 result.into()
129 }
130}
131
132impl From<Error> for Robj {
134 fn from(res: Error) -> Self {
135 res.to_string().into()
136 }
137}
138impl From<Error> for String {
139 fn from(res: Error) -> Self {
140 res.to_string()
141 }
142}
143
144impl From<&Robj> for Robj {
146 fn from(val: &Robj) -> Self {
149 unsafe { Robj::from_sexp(val.get()) }
150 }
151}
152
153pub trait IntoRobj {
158 fn into_robj(self) -> Robj;
159}
160
161impl<T> IntoRobj for T
162where
163 Robj: From<T>,
164{
165 fn into_robj(self) -> Robj {
166 self.into()
167 }
168}
169
170pub trait ToVectorValue {
174 fn sexptype() -> SEXPTYPE {
175 SEXPTYPE::NILSXP
176 }
177
178 fn to_real(&self) -> f64
179 where
180 Self: Sized,
181 {
182 0.
183 }
184
185 fn to_complex(&self) -> Rcomplex
186 where
187 Self: Sized,
188 {
189 Rcomplex { r: 0., i: 0. }
190 }
191
192 fn to_integer(&self) -> i32
193 where
194 Self: Sized,
195 {
196 i32::MIN
197 }
198
199 fn to_logical(&self) -> i32
200 where
201 Self: Sized,
202 {
203 i32::MIN
204 }
205
206 fn to_raw(&self) -> u8
207 where
208 Self: Sized,
209 {
210 0
211 }
212
213 fn to_sexp(&self) -> SEXP
214 where
215 Self: Sized,
216 {
217 unsafe { R_NilValue }
218 }
219}
220
221macro_rules! impl_real_tvv {
222 ($t: ty) => {
223 impl ToVectorValue for $t {
224 fn sexptype() -> SEXPTYPE {
225 SEXPTYPE::REALSXP
226 }
227
228 fn to_real(&self) -> f64 {
229 *self as f64
230 }
231 }
232
233 impl ToVectorValue for &$t {
234 fn sexptype() -> SEXPTYPE {
235 SEXPTYPE::REALSXP
236 }
237
238 fn to_real(&self) -> f64 {
239 **self as f64
240 }
241 }
242
243 impl ToVectorValue for Option<$t> {
244 fn sexptype() -> SEXPTYPE {
245 SEXPTYPE::REALSXP
246 }
247
248 fn to_real(&self) -> f64 {
249 if self.is_some() {
250 self.unwrap() as f64
251 } else {
252 unsafe { R_NaReal }
253 }
254 }
255 }
256 };
257}
258
259impl_real_tvv!(f64);
260impl_real_tvv!(f32);
261
262impl_real_tvv!(i64);
265impl_real_tvv!(u32);
266impl_real_tvv!(u64);
267impl_real_tvv!(usize);
268
269macro_rules! impl_complex_tvv {
270 ($t: ty) => {
271 impl ToVectorValue for $t {
272 fn sexptype() -> SEXPTYPE {
273 SEXPTYPE::CPLXSXP
274 }
275
276 fn to_complex(&self) -> Rcomplex {
277 unsafe { std::mem::transmute(*self) }
278 }
279 }
280
281 impl ToVectorValue for &$t {
282 fn sexptype() -> SEXPTYPE {
283 SEXPTYPE::CPLXSXP
284 }
285
286 fn to_complex(&self) -> Rcomplex {
287 unsafe { std::mem::transmute(**self) }
288 }
289 }
290 };
291}
292
293impl_complex_tvv!(c64);
294impl_complex_tvv!(Rcplx);
295impl_complex_tvv!((f64, f64));
296
297macro_rules! impl_integer_tvv {
298 ($t: ty) => {
299 impl ToVectorValue for $t {
300 fn sexptype() -> SEXPTYPE {
301 SEXPTYPE::INTSXP
302 }
303
304 fn to_integer(&self) -> i32 {
305 *self as i32
306 }
307 }
308
309 impl ToVectorValue for &$t {
310 fn sexptype() -> SEXPTYPE {
311 SEXPTYPE::INTSXP
312 }
313
314 fn to_integer(&self) -> i32 {
315 **self as i32
316 }
317 }
318
319 impl ToVectorValue for Option<$t> {
320 fn sexptype() -> SEXPTYPE {
321 SEXPTYPE::INTSXP
322 }
323
324 fn to_integer(&self) -> i32 {
325 if self.is_some() {
326 self.unwrap() as i32
327 } else {
328 unsafe { R_NaInt }
329 }
330 }
331 }
332 };
333}
334
335impl_integer_tvv!(i8);
336impl_integer_tvv!(i16);
337impl_integer_tvv!(i32);
338impl_integer_tvv!(u16);
339
340impl ToVectorValue for u8 {
341 fn sexptype() -> SEXPTYPE {
342 SEXPTYPE::RAWSXP
343 }
344
345 fn to_raw(&self) -> u8 {
346 *self
347 }
348}
349
350impl ToVectorValue for &u8 {
351 fn sexptype() -> SEXPTYPE {
352 SEXPTYPE::RAWSXP
353 }
354
355 fn to_raw(&self) -> u8 {
356 **self
357 }
358}
359
360macro_rules! impl_str_tvv {
361 ($t: ty) => {
362 impl ToVectorValue for $t {
363 fn sexptype() -> SEXPTYPE {
364 SEXPTYPE::STRSXP
365 }
366
367 fn to_sexp(&self) -> SEXP
368 where
369 Self: Sized,
370 {
371 str_to_character(self.as_ref())
372 }
373 }
374
375 impl ToVectorValue for &$t {
376 fn sexptype() -> SEXPTYPE {
377 SEXPTYPE::STRSXP
378 }
379
380 fn to_sexp(&self) -> SEXP
381 where
382 Self: Sized,
383 {
384 str_to_character(self.as_ref())
385 }
386 }
387
388 impl ToVectorValue for Option<$t> {
389 fn sexptype() -> SEXPTYPE {
390 SEXPTYPE::STRSXP
391 }
392
393 fn to_sexp(&self) -> SEXP
394 where
395 Self: Sized,
396 {
397 if let Some(s) = self {
398 str_to_character(s.as_ref())
399 } else {
400 unsafe { R_NaString }
401 }
402 }
403 }
404 };
405}
406
407impl_str_tvv! {&str}
408impl_str_tvv! {String}
409
410impl ToVectorValue for Rstr {
411 fn sexptype() -> SEXPTYPE {
412 SEXPTYPE::STRSXP
413 }
414
415 fn to_sexp(&self) -> SEXP
416 where
417 Self: Sized,
418 {
419 unsafe { self.get() }
420 }
421}
422
423impl ToVectorValue for &Rstr {
424 fn sexptype() -> SEXPTYPE {
425 SEXPTYPE::STRSXP
426 }
427
428 fn to_sexp(&self) -> SEXP
429 where
430 Self: Sized,
431 {
432 unsafe { self.get() }
433 }
434}
435
436impl ToVectorValue for Option<Rstr> {
437 fn sexptype() -> SEXPTYPE {
438 SEXPTYPE::STRSXP
439 }
440
441 fn to_sexp(&self) -> SEXP
442 where
443 Self: Sized,
444 {
445 if let Some(s) = self {
446 unsafe { s.get() }
447 } else {
448 unsafe { R_NaString }
449 }
450 }
451}
452
453impl TryFrom<&Robj> for Rstr {
454 type Error = crate::Error;
455
456 fn try_from(robj: &Robj) -> Result<Self> {
457 let sexptype = robj.sexptype();
458 if let SEXPTYPE::STRSXP = sexptype {
459 if robj.len() == 1 {
460 let strs = Strings::try_from(robj)?;
461 Ok(strs.elt(0))
462 } else {
463 Err(Error::ExpectedRstr(robj.clone()))
464 }
465 } else if let SEXPTYPE::CHARSXP = sexptype {
466 Ok(Rstr { robj: robj.clone() })
467 } else {
468 Err(Error::ExpectedRstr(robj.clone()))
469 }
470 }
471}
472
473impl TryFrom<Robj> for Rstr {
474 type Error = crate::Error;
475
476 fn try_from(value: Robj) -> std::result::Result<Self, Self::Error> {
477 Self::try_from(&value)
478 }
479}
480
481impl GetSexp for Rstr {
482 unsafe fn get(&self) -> SEXP {
483 self.robj.get()
484 }
485
486 unsafe fn get_mut(&mut self) -> SEXP {
487 self.robj.get_mut()
488 }
489
490 fn as_robj(&self) -> &Robj {
491 &self.robj
492 }
493
494 fn as_robj_mut(&mut self) -> &mut Robj {
495 &mut self.robj
496 }
497}
498
499impl Length for Rstr {}
501impl Types for Rstr {}
502impl Conversions for Rstr {}
503impl Rinternals for Rstr {}
504impl Slices for Rstr {}
505impl Operators for Rstr {}
506
507impl ToVectorValue for bool {
508 fn sexptype() -> SEXPTYPE {
509 SEXPTYPE::LGLSXP
510 }
511
512 fn to_logical(&self) -> i32
513 where
514 Self: Sized,
515 {
516 *self as i32
517 }
518}
519
520impl ToVectorValue for &bool {
521 fn sexptype() -> SEXPTYPE {
522 SEXPTYPE::LGLSXP
523 }
524
525 fn to_logical(&self) -> i32
526 where
527 Self: Sized,
528 {
529 **self as i32
530 }
531}
532
533impl ToVectorValue for Rbool {
534 fn sexptype() -> SEXPTYPE {
535 SEXPTYPE::LGLSXP
536 }
537
538 fn to_logical(&self) -> i32
539 where
540 Self: Sized,
541 {
542 self.0
543 }
544}
545
546impl ToVectorValue for &Rbool {
547 fn sexptype() -> SEXPTYPE {
548 SEXPTYPE::LGLSXP
549 }
550
551 fn to_logical(&self) -> i32
552 where
553 Self: Sized,
554 {
555 self.0
556 }
557}
558
559impl ToVectorValue for Option<bool> {
560 fn sexptype() -> SEXPTYPE {
561 SEXPTYPE::LGLSXP
562 }
563
564 fn to_logical(&self) -> i32 {
565 if self.is_some() {
566 self.unwrap() as i32
567 } else {
568 unsafe { R_NaInt }
569 }
570 }
571}
572
573impl<T> From<&Option<T>> for Robj
574where
575 Option<T>: ToVectorValue + Clone,
576{
577 fn from(value: &Option<T>) -> Self {
578 value.clone().into()
579 }
580}
581
582fn fixed_size_collect<I>(iter: I, len: usize) -> Robj
584where
585 I: Iterator,
586 I: Sized,
587 I::Item: ToVectorValue,
588{
589 single_threaded(|| unsafe {
590 let sexptype = I::Item::sexptype();
592 if sexptype != SEXPTYPE::NILSXP {
593 let res = Robj::alloc_vector(sexptype, len);
594 let sexp = res.get();
595 match sexptype {
596 SEXPTYPE::REALSXP => {
597 let ptr = REAL(sexp);
598 for (i, v) in iter.enumerate() {
599 *ptr.add(i) = v.to_real();
600 }
601 }
602 SEXPTYPE::CPLXSXP => {
603 let ptr = COMPLEX(sexp);
604 for (i, v) in iter.enumerate() {
605 *ptr.add(i) = v.to_complex();
606 }
607 }
608 SEXPTYPE::INTSXP => {
609 let ptr = INTEGER(sexp);
610 for (i, v) in iter.enumerate() {
611 *ptr.add(i) = v.to_integer();
612 }
613 }
614 SEXPTYPE::LGLSXP => {
615 let ptr = LOGICAL(sexp);
616 for (i, v) in iter.enumerate() {
617 *ptr.add(i) = v.to_logical();
618 }
619 }
620 SEXPTYPE::STRSXP => {
621 for (i, v) in iter.enumerate() {
622 SET_STRING_ELT(sexp, i as isize, v.to_sexp());
623 }
624 }
625 SEXPTYPE::RAWSXP => {
626 let ptr = RAW(sexp);
627 for (i, v) in iter.enumerate() {
628 *ptr.add(i) = v.to_raw();
629 }
630 }
631 _ => {
632 panic!("unexpected SEXPTYPE in collect_robj");
633 }
634 }
635 res
636 } else {
637 Robj::from(())
638 }
639 })
640}
641
642pub trait RobjItertools: Iterator {
644 fn collect_robj(self) -> Robj
667 where
668 Self: Iterator,
669 Self: Sized,
670 Self::Item: ToVectorValue,
671 {
672 if let (len, Some(max)) = self.size_hint() {
673 if len == max {
674 return fixed_size_collect(self, len);
675 }
676 }
677 let vec: Vec<_> = self.collect();
679 assert!(vec.iter().size_hint() == (vec.len(), Some(vec.len())));
680 vec.into_iter().collect_robj()
681 }
682
683 fn collect_rarray<const LEN: usize>(self, dims: [usize; LEN]) -> Result<RArray<Self::Item, LEN>>
690 where
691 Self: Iterator,
692 Self: Sized,
693 Self::Item: ToVectorValue,
694 Robj: for<'a> AsTypedSlice<'a, Self::Item>,
695 {
696 let mut vector = self.collect_robj();
697 let prod = dims.iter().product::<usize>();
698 if prod != vector.len() {
699 return Err(Error::Other(format!(
700 "The vector length ({}) does not match the length implied by the dimensions ({})",
701 vector.len(),
702 prod
703 )));
704 }
705 vector.set_attrib(wrapper::symbol::dim_symbol(), dims.iter().collect_robj())?;
706 let _data = vector.as_typed_slice().ok_or(Error::Other(
707 "Unknown error in converting to slice".to_string(),
708 ))?;
709 Ok(RArray::from_parts(vector))
710 }
711}
712
713impl<T> RobjItertools for T where T: Iterator {}
715
716impl<T> From<T> for Robj
718where
719 T: ToVectorValue,
720{
721 fn from(scalar: T) -> Self {
722 Some(scalar).into_iter().collect_robj()
723 }
724}
725
726macro_rules! impl_from_as_iterator {
727 ($t: ty) => {
728 impl<T> From<$t> for Robj
729 where
730 $t: RobjItertools,
731 <$t as Iterator>::Item: ToVectorValue,
732 T: ToVectorValue,
733 {
734 fn from(val: $t) -> Self {
735 val.collect_robj()
736 }
737 }
738 };
739}
740
741impl<T, const N: usize> From<[T; N]> for Robj
753where
754 T: ToVectorValue,
755{
756 fn from(val: [T; N]) -> Self {
757 fixed_size_collect(val.into_iter(), N)
758 }
759}
760
761impl<'a, T, const N: usize> From<&'a [T; N]> for Robj
762where
763 Self: 'a,
764 &'a T: ToVectorValue + 'a,
765{
766 fn from(val: &'a [T; N]) -> Self {
767 fixed_size_collect(val.iter(), N)
768 }
769}
770
771impl<'a, T, const N: usize> From<&'a mut [T; N]> for Robj
772where
773 Self: 'a,
774 &'a mut T: ToVectorValue + 'a,
775{
776 fn from(val: &'a mut [T; N]) -> Self {
777 fixed_size_collect(val.iter_mut(), N)
778 }
779}
780
781impl<T: ToVectorValue + Clone> From<&Vec<T>> for Robj {
782 fn from(value: &Vec<T>) -> Self {
783 let len = value.len();
784 fixed_size_collect(value.iter().cloned(), len)
785 }
786}
787
788impl<T: ToVectorValue> From<Vec<T>> for Robj {
789 fn from(value: Vec<T>) -> Self {
790 let len = value.len();
791 fixed_size_collect(value.into_iter(), len)
792 }
793}
794
795impl<'a, T> From<&'a [T]> for Robj
796where
797 Self: 'a,
798 T: 'a,
799 &'a T: ToVectorValue,
800{
801 fn from(val: &'a [T]) -> Self {
802 val.iter().collect_robj()
803 }
804}
805
806impl_from_as_iterator! {Range<T>}
807impl_from_as_iterator! {RangeInclusive<T>}
808
809impl From<Vec<Robj>> for Robj {
810 fn from(val: Vec<Robj>) -> Self {
812 Self::from(&val)
813 }
814}
815
816impl From<&Vec<Robj>> for Robj {
817 fn from(val: &Vec<Robj>) -> Self {
818 List::from_values(val.iter()).into()
819 }
820}
821
822#[cfg(test)]
823mod test {
824 use super::*;
825 use crate as extendr_api;
826
827 #[test]
828 fn test_vec_rint_to_robj() {
829 test! {
830 let int_vec = vec![3,4,0,-2];
831 let int_vec_robj: Robj = int_vec.clone().into();
832 assert_eq!(int_vec_robj.as_integer_slice().unwrap(), &int_vec);
834
835 let rint_vec = vec![Rint::from(3), Rint::from(4), Rint::from(0), Rint::from(-2)];
836 let rint_vec_robj: Robj = rint_vec.into();
837 assert_eq!(rint_vec_robj.as_integer_slice().unwrap(), &int_vec);
839 }
840 }
841
842 #[test]
843 fn test_collect_rarray_matrix() {
844 test! {
845 let rmat = (1i32..=16).collect_rarray([4, 4]);
847 assert!(rmat.is_ok());
848 assert_eq!(Robj::from(rmat), R!("matrix(1:16, nrow=4)").unwrap());
849 }
850 }
851
852 #[test]
853 fn test_collect_rarray_tensor() {
854 test! {
855 let rmat = (1i32..=16).collect_rarray([2, 4, 2]);
857 assert!(rmat.is_ok());
858 assert_eq!(Robj::from(rmat), R!("array(1:16, dim=c(2, 4, 2))").unwrap());
859 }
860 }
861
862 #[test]
863 fn test_collect_rarray_matrix_failure() {
864 test! {
865 let rmat = (1i32..=16).collect_rarray([3, 3]);
867 assert!(rmat.is_err());
868 let msg = rmat.unwrap_err().to_string();
869 assert!(msg.contains('9'));
870 assert!(msg.contains("dimension"));
871 }
872 }
873
874 #[test]
875 fn test_collect_tensor_failure() {
876 test! {
877 let rmat = (1i32..=16).collect_rarray([3, 3, 3]);
879 assert!(rmat.is_err());
880 let msg = rmat.unwrap_err().to_string();
881 assert!(msg.contains("27"));
882 assert!(msg.contains("dimension"));
883 }
884 }
885
886 #[test]
887 #[cfg(all(feature = "result_condition", not(feature = "result_list")))]
888 fn test_result_condition() {
889 use crate::prelude::*;
890 fn my_err_f() -> std::result::Result<f64, f64> {
891 Err(42.0) }
893
894 test! {
895 assert_eq!(
896 r!(my_err_f()),
897 R!(
898 "structure(list(message = 'extendr_err',
899 value = 42.0), class = c('extendr_error', 'error', 'condition'))"
900 ).unwrap()
901 );
902 }
903 }
904
905 #[test]
906 #[cfg(feature = "result_list")]
907 fn test_result_list() {
908 use crate::prelude::*;
909 fn my_err_f() -> std::result::Result<f64, String> {
910 Err("We have water in the engine room!".to_string())
911 }
912
913 fn my_ok_f() -> std::result::Result<f64, String> {
914 Ok(123.123)
915 }
916
917 test! {
918 assert_eq!(
919 r!(my_err_f()),
920 R!("x=list(ok=NULL, err='We have water in the engine room!')
921 class(x)='extendr_result'
922 x"
923 ).unwrap()
924 );
925 assert_eq!(
926 r!(my_ok_f()),
927 R!("x = list(ok=123.123, err=NULL)
928 class(x)='extendr_result'
929 x"
930 ).unwrap()
931 );
932 }
933 }
934}