Repository: extendr/extendr (rust)

Issue:
Return type i64, u64, and u32 should be converted to REALSXP
While we now can use `use_try_from = true` for type-checking, `TryFrom` is implemented one-way (R to Rust), if I understand correctly

I'm wondering what should happen in this case.

``` r
rextendr::rust_function(r"(
fn f() -> i64 {
  i64::MAX
}
)",
  patch.crates_io = list(`extendr-api` = list(git = "https://github.com/extendr/extendr")),
)
#> ℹ build directory: '/tmp/RtmpR1VmHe/file161681b33c70a'
#> ✓ Writing '/tmp/RtmpR1VmHe/file161681b33c70a/target/extendr_wrappers.R'.

f()
#> [1] -1
```

<sup>Created on 2021-07-23 by the [reprex package](https://reprex.tidyverse.org) (v2.0.0)</sup>

Pull request:
Return REALSXP when the type can exceed R's integer range
Fix #240 

Patch:
diff --git a/extendr-api/src/lib.rs b/extendr-api/src/lib.rs
index 531887db6..0c9823f20 100644
--- a/extendr-api/src/lib.rs
+++ b/extendr-api/src/lib.rs
@@ -657,12 +657,12 @@ mod tests {
                 // General integer types.
                 assert_eq!(new_owned(wrap__return_u8()), Robj::from(123));
                 assert_eq!(new_owned(wrap__return_u16()), Robj::from(123));
-                assert_eq!(new_owned(wrap__return_u32()), Robj::from(123));
-                assert_eq!(new_owned(wrap__return_u64()), Robj::from(123));
+                assert_eq!(new_owned(wrap__return_u32()), Robj::from(123.));
+                assert_eq!(new_owned(wrap__return_u64()), Robj::from(123.));
                 assert_eq!(new_owned(wrap__return_i8()), Robj::from(123));
                 assert_eq!(new_owned(wrap__return_i16()), Robj::from(123));
                 assert_eq!(new_owned(wrap__return_i32()), Robj::from(123));
-                assert_eq!(new_owned(wrap__return_i64()), Robj::from(123));
+                assert_eq!(new_owned(wrap__return_i64()), Robj::from(123.));
 
                 // Floating point types.
                 assert_eq!(new_owned(wrap__return_f32()), Robj::from(123.));
diff --git a/extendr-api/src/robj/into_robj.rs b/extendr-api/src/robj/into_robj.rs
index 5fc0bcfa0..8bb389f19 100644
--- a/extendr-api/src/robj/into_robj.rs
+++ b/extendr-api/src/robj/into_robj.rs
@@ -150,6 +150,12 @@ macro_rules! impl_real_tvv {
 
 impl_real_tvv!(f64);
 impl_real_tvv!(f32);
+
+// Since these types might exceeds the max or min of R's 32bit integer, we need
+// to return as REALSXP
+impl_real_tvv!(i64);
+impl_real_tvv!(u32);
+impl_real_tvv!(u64);
 impl_real_tvv!(usize);
 
 macro_rules! impl_integer_tvv {
@@ -193,11 +199,8 @@ macro_rules! impl_integer_tvv {
 impl_integer_tvv!(i8);
 impl_integer_tvv!(i16);
 impl_integer_tvv!(i32);
-impl_integer_tvv!(i64);
 impl_integer_tvv!(u8);
 impl_integer_tvv!(u16);
-impl_integer_tvv!(u32);
-impl_integer_tvv!(u64);
 
 macro_rules! impl_str_tvv {
     ($t: ty) => {


Test patch:
diff --git a/extendr-api/src/robj/tests.rs b/extendr-api/src/robj/tests.rs
index 8678bdff6..328b6cd29 100644
--- a/extendr-api/src/robj/tests.rs
+++ b/extendr-api/src/robj/tests.rs
@@ -225,15 +225,25 @@ fn test_to_robj() {
         assert_eq!(Robj::from(true), Robj::from([Bool::from(true)]));
         //assert_eq!(Robj::from(1_u8), Robj::from(1));
         assert_eq!(Robj::from(1_u16), Robj::from(1));
-        assert_eq!(Robj::from(1_u32), Robj::from(1));
-        assert_eq!(Robj::from(1_u64), Robj::from(1));
+        assert_eq!(Robj::from(1_u32), Robj::from(1.));
+        assert_eq!(Robj::from(1_u64), Robj::from(1.));
+        assert_eq!(Robj::from(1_usize), Robj::from(1.));
         assert_eq!(Robj::from(1_i8), Robj::from(1));
         assert_eq!(Robj::from(1_i16), Robj::from(1));
         assert_eq!(Robj::from(1_i32), Robj::from(1));
-        assert_eq!(Robj::from(1_i64), Robj::from(1));
+        assert_eq!(Robj::from(1_i64), Robj::from(1.));
         assert_eq!(Robj::from(1.0_f32), Robj::from(1.));
         assert_eq!(Robj::from(1.0_f64), Robj::from(1.));
 
+        // check large values
+        assert_eq!(Robj::from(i64::MAX), Robj::from(i64::MAX as f64));
+        assert_eq!(Robj::from(i64::MIN), Robj::from(i64::MIN as f64));
+
+        // check NaN and Inf
+        assert_eq!(Robj::from(f64::NAN), R!("NaN")?);
+        assert_eq!(Robj::from(f64::INFINITY), R!("Inf")?);
+        assert_eq!(Robj::from(-f64::INFINITY), R!("-Inf")?);
+
         let ab = Robj::from(vec!["a", "b"]);
         let ab2 = Robj::from(vec!["a".to_string(), "b".to_string()]);
         assert_eq!(ab, ab2);