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 match res {
72 Ok(val) => val.into(),
73 Err(err) => panic!("{}", err),
74 }
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 i32::MIN
200 }
201
202 fn to_logical(&self) -> i32
203 where
204 Self: Sized,
205 {
206 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 Rstr {
414 fn sexptype() -> SEXPTYPE {
415 SEXPTYPE::STRSXP
416 }
417
418 fn to_sexp(&self) -> SEXP
419 where
420 Self: Sized,
421 {
422 unsafe { self.get() }
423 }
424}
425
426impl ToVectorValue for &Rstr {
427 fn sexptype() -> SEXPTYPE {
428 SEXPTYPE::STRSXP
429 }
430
431 fn to_sexp(&self) -> SEXP
432 where
433 Self: Sized,
434 {
435 unsafe { self.get() }
436 }
437}
438
439impl ToVectorValue for Option<Rstr> {
440 fn sexptype() -> SEXPTYPE {
441 SEXPTYPE::STRSXP
442 }
443
444 fn to_sexp(&self) -> SEXP
445 where
446 Self: Sized,
447 {
448 if let Some(s) = self {
449 unsafe { s.get() }
450 } else {
451 unsafe { R_NaString }
452 }
453 }
454}
455
456impl TryFrom<&Robj> for Rstr {
457 type Error = crate::Error;
458
459 fn try_from(robj: &Robj) -> Result<Self> {
460 let sexptype = robj.sexptype();
461 if let SEXPTYPE::STRSXP = sexptype {
462 if robj.len() == 1 {
463 let strs = Strings::try_from(robj)?;
464 Ok(strs.elt(0))
465 } else {
466 Err(Error::ExpectedRstr(robj.clone()))
467 }
468 } else if let SEXPTYPE::CHARSXP = sexptype {
469 Ok(Rstr { robj: robj.clone() })
470 } else {
471 Err(Error::ExpectedRstr(robj.clone()))
472 }
473 }
474}
475
476impl TryFrom<Robj> for Rstr {
477 type Error = crate::Error;
478
479 fn try_from(value: Robj) -> std::result::Result<Self, Self::Error> {
480 Self::try_from(&value)
481 }
482}
483
484impl GetSexp for Rstr {
485 unsafe fn get(&self) -> SEXP {
486 self.robj.get()
487 }
488
489 unsafe fn get_mut(&mut self) -> SEXP {
490 self.robj.get_mut()
491 }
492
493 fn as_robj(&self) -> &Robj {
494 &self.robj
495 }
496
497 fn as_robj_mut(&mut self) -> &mut Robj {
498 &mut self.robj
499 }
500}
501
502impl Length for Rstr {}
504impl Types for Rstr {}
505impl Conversions for Rstr {}
506impl Rinternals for Rstr {}
507impl Slices for Rstr {}
508impl Operators for Rstr {}
509
510impl ToVectorValue for bool {
511 fn sexptype() -> SEXPTYPE {
512 SEXPTYPE::LGLSXP
513 }
514
515 fn to_logical(&self) -> i32
516 where
517 Self: Sized,
518 {
519 *self as i32
520 }
521}
522
523impl ToVectorValue for &bool {
524 fn sexptype() -> SEXPTYPE {
525 SEXPTYPE::LGLSXP
526 }
527
528 fn to_logical(&self) -> i32
529 where
530 Self: Sized,
531 {
532 **self as i32
533 }
534}
535
536impl ToVectorValue for Rbool {
537 fn sexptype() -> SEXPTYPE {
538 SEXPTYPE::LGLSXP
539 }
540
541 fn to_logical(&self) -> i32
542 where
543 Self: Sized,
544 {
545 self.0
546 }
547}
548
549impl ToVectorValue for &Rbool {
550 fn sexptype() -> SEXPTYPE {
551 SEXPTYPE::LGLSXP
552 }
553
554 fn to_logical(&self) -> i32
555 where
556 Self: Sized,
557 {
558 self.0
559 }
560}
561
562impl ToVectorValue for Option<bool> {
563 fn sexptype() -> SEXPTYPE {
564 SEXPTYPE::LGLSXP
565 }
566
567 fn to_logical(&self) -> i32 {
568 if self.is_some() {
569 self.unwrap() as i32
570 } else {
571 unsafe { R_NaInt }
572 }
573 }
574}
575
576impl<T> From<&Option<T>> for Robj
577where
578 Option<T>: ToVectorValue + Clone,
579{
580 fn from(value: &Option<T>) -> Self {
581 value.clone().into()
582 }
583}
584
585fn fixed_size_collect<I>(iter: I, len: usize) -> Robj
587where
588 I: Iterator,
589 I: Sized,
590 I::Item: ToVectorValue,
591{
592 single_threaded(|| unsafe {
593 let sexptype = I::Item::sexptype();
595 if sexptype != SEXPTYPE::NILSXP {
596 let res = Robj::alloc_vector(sexptype, len);
597 let sexp = res.get();
598 match sexptype {
599 SEXPTYPE::REALSXP => {
600 let ptr = REAL(sexp);
601 for (i, v) in iter.enumerate() {
602 *ptr.add(i) = v.to_real();
603 }
604 }
605 SEXPTYPE::CPLXSXP => {
606 let ptr = COMPLEX(sexp);
607 for (i, v) in iter.enumerate() {
608 *ptr.add(i) = v.to_complex();
609 }
610 }
611 SEXPTYPE::INTSXP => {
612 let ptr = INTEGER(sexp);
613 for (i, v) in iter.enumerate() {
614 *ptr.add(i) = v.to_integer();
615 }
616 }
617 SEXPTYPE::LGLSXP => {
618 let ptr = LOGICAL(sexp);
619 for (i, v) in iter.enumerate() {
620 *ptr.add(i) = v.to_logical();
621 }
622 }
623 SEXPTYPE::STRSXP => {
624 for (i, v) in iter.enumerate() {
625 SET_STRING_ELT(sexp, i as isize, v.to_sexp());
626 }
627 }
628 SEXPTYPE::RAWSXP => {
629 let ptr = RAW(sexp);
630 for (i, v) in iter.enumerate() {
631 *ptr.add(i) = v.to_raw();
632 }
633 }
634 _ => {
635 panic!("unexpected SEXPTYPE in collect_robj");
636 }
637 }
638 res
639 } else {
640 Robj::from(())
641 }
642 })
643}
644
645pub trait RobjItertools: Iterator {
647 fn collect_robj(self) -> Robj
670 where
671 Self: Iterator,
672 Self: Sized,
673 Self::Item: ToVectorValue,
674 {
675 if let (len, Some(max)) = self.size_hint() {
676 if len == max {
677 return fixed_size_collect(self, len);
678 }
679 }
680 let vec: Vec<_> = self.collect();
682 assert!(vec.iter().size_hint() == (vec.len(), Some(vec.len())));
683 vec.into_iter().collect_robj()
684 }
685
686 fn collect_rarray<const LEN: usize>(self, dims: [usize; LEN]) -> Result<RArray<Self::Item, LEN>>
693 where
694 Self: Iterator,
695 Self: Sized,
696 Self::Item: ToVectorValue,
697 Robj: for<'a> AsTypedSlice<'a, Self::Item>,
698 {
699 let mut vector = self.collect_robj();
700 let prod = dims.iter().product::<usize>();
701 if prod != vector.len() {
702 return Err(Error::Other(format!(
703 "The vector length ({}) does not match the length implied by the dimensions ({})",
704 vector.len(),
705 prod
706 )));
707 }
708 vector.set_attrib(wrapper::symbol::dim_symbol(), dims.iter().collect_robj())?;
709 let _data = vector.as_typed_slice().ok_or(Error::Other(
710 "Unknown error in converting to slice".to_string(),
711 ))?;
712 Ok(RArray::from_parts(vector))
713 }
714}
715
716impl<T> RobjItertools for T where T: Iterator {}
718
719impl<T> From<T> for Robj
721where
722 T: ToVectorValue,
723{
724 fn from(scalar: T) -> Self {
725 Some(scalar).into_iter().collect_robj()
726 }
727}
728
729macro_rules! impl_from_as_iterator {
730 ($t: ty) => {
731 impl<T> From<$t> for Robj
732 where
733 $t: RobjItertools,
734 <$t as Iterator>::Item: ToVectorValue,
735 T: ToVectorValue,
736 {
737 fn from(val: $t) -> Self {
738 val.collect_robj()
739 }
740 }
741 };
742}
743
744impl<T, const N: usize> From<[T; N]> for Robj
756where
757 T: ToVectorValue,
758{
759 fn from(val: [T; N]) -> Self {
760 fixed_size_collect(val.into_iter(), N)
761 }
762}
763
764impl<'a, T, const N: usize> From<&'a [T; N]> for Robj
765where
766 Self: 'a,
767 &'a T: ToVectorValue + 'a,
768{
769 fn from(val: &'a [T; N]) -> Self {
770 fixed_size_collect(val.iter(), N)
771 }
772}
773
774impl<'a, T, const N: usize> From<&'a mut [T; N]> for Robj
775where
776 Self: 'a,
777 &'a mut T: ToVectorValue + 'a,
778{
779 fn from(val: &'a mut [T; N]) -> Self {
780 fixed_size_collect(val.iter_mut(), N)
781 }
782}
783
784impl<T: ToVectorValue + Clone> From<&Vec<T>> for Robj {
785 fn from(value: &Vec<T>) -> Self {
786 let len = value.len();
787 fixed_size_collect(value.iter().cloned(), len)
788 }
789}
790
791impl<T: ToVectorValue> From<Vec<T>> for Robj {
792 fn from(value: Vec<T>) -> Self {
793 let len = value.len();
794 fixed_size_collect(value.into_iter(), len)
795 }
796}
797
798impl<'a, T> From<&'a [T]> for Robj
799where
800 Self: 'a,
801 T: 'a,
802 &'a T: ToVectorValue,
803{
804 fn from(val: &'a [T]) -> Self {
805 val.iter().collect_robj()
806 }
807}
808
809impl_from_as_iterator! {Range<T>}
810impl_from_as_iterator! {RangeInclusive<T>}
811
812impl From<Vec<Robj>> for Robj {
813 fn from(val: Vec<Robj>) -> Self {
815 Self::from(&val)
816 }
817}
818
819impl From<&Vec<Robj>> for Robj {
820 fn from(val: &Vec<Robj>) -> Self {
821 List::from_values(val.iter()).into()
822 }
823}
824
825#[cfg(test)]
826mod test {
827 use super::*;
828 use crate as extendr_api;
829
830 #[test]
831 fn test_vec_rint_to_robj() {
832 test! {
833 let int_vec = vec![3,4,0,-2];
834 let int_vec_robj: Robj = int_vec.clone().into();
835 assert_eq!(int_vec_robj.as_integer_slice().unwrap(), &int_vec);
837
838 let rint_vec = vec![Rint::from(3), Rint::from(4), Rint::from(0), Rint::from(-2)];
839 let rint_vec_robj: Robj = rint_vec.into();
840 assert_eq!(rint_vec_robj.as_integer_slice().unwrap(), &int_vec);
842 }
843 }
844
845 #[test]
846 fn test_collect_rarray_matrix() {
847 test! {
848 let rmat = (1i32..=16).collect_rarray([4, 4]);
850 assert!(rmat.is_ok());
851 assert_eq!(Robj::from(rmat), R!("matrix(1:16, nrow=4)").unwrap());
852 }
853 }
854
855 #[test]
856 fn test_collect_rarray_tensor() {
857 test! {
858 let rmat = (1i32..=16).collect_rarray([2, 4, 2]);
860 assert!(rmat.is_ok());
861 assert_eq!(Robj::from(rmat), R!("array(1:16, dim=c(2, 4, 2))").unwrap());
862 }
863 }
864
865 #[test]
866 fn test_collect_rarray_matrix_failure() {
867 test! {
868 let rmat = (1i32..=16).collect_rarray([3, 3]);
870 assert!(rmat.is_err());
871 let msg = rmat.unwrap_err().to_string();
872 assert!(msg.contains('9'));
873 assert!(msg.contains("dimension"));
874 }
875 }
876
877 #[test]
878 fn test_collect_tensor_failure() {
879 test! {
880 let rmat = (1i32..=16).collect_rarray([3, 3, 3]);
882 assert!(rmat.is_err());
883 let msg = rmat.unwrap_err().to_string();
884 assert!(msg.contains("27"));
885 assert!(msg.contains("dimension"));
886 }
887 }
888
889 #[test]
890 #[cfg(all(feature = "result_condition", not(feature = "result_list")))]
891 fn test_result_condition() {
892 use crate::prelude::*;
893 fn my_err_f() -> std::result::Result<f64, f64> {
894 Err(42.0) }
896
897 test! {
898 assert_eq!(
899 r!(my_err_f()),
900 R!(
901 "structure(list(message = 'extendr_err',
902 value = 42.0), class = c('extendr_error', 'error', 'condition'))"
903 ).unwrap()
904 );
905 }
906 }
907
908 #[test]
909 #[cfg(feature = "result_list")]
910 fn test_result_list() {
911 use crate::prelude::*;
912 fn my_err_f() -> std::result::Result<f64, String> {
913 Err("We have water in the engine room!".to_string())
914 }
915
916 fn my_ok_f() -> std::result::Result<f64, String> {
917 Ok(123.123)
918 }
919
920 test! {
921 assert_eq!(
922 r!(my_err_f()),
923 R!("x=list(ok=NULL, err='We have water in the engine room!')
924 class(x)='extendr_result'
925 x"
926 ).unwrap()
927 );
928 assert_eq!(
929 r!(my_ok_f()),
930 R!("x = list(ok=123.123, err=NULL)
931 class(x)='extendr_result'
932 x"
933 ).unwrap()
934 );
935 }
936 }
937}