Repository: extendr/extendr
Pull request #723 (2024-04-06 12:06:27)

Fix `#[extendr]` conversions into `Dataframe<T>`
Addressing #715



CGMossa: This issue has two parts. It is not possible to use it like so:

```rs
#[derive(IntoDataFrameRow)]
struct Row {
    name: u32,
}

#[extendr]
fn dataframe_conversion(data_frame: Dataframe<Row>) -> Robj {
    vec![Row { name: 42 }].into_dataframe().unwrap().into_robj()
}
```

CGMossa: Please take a look again, as this PR fixes things that didn't work before. See the linked issue. 
CGMossa: @Ilia-Kosenkov 
Ilia-Kosenkov: Here, I found how you can test that these functions actually work as intended, including conversions
https://github.com/extendr/extendr/blob/e61fc0a6c9e963e08df0f39a3bddb9a48bdacfe4/extendr-api/src/lib.rs#L815-L864
CGMossa: > Here, I found how you can test that these functions actually work as intended, including conversions
> 
> https://github.com/extendr/extendr/blob/e61fc0a6c9e963e08df0f39a3bddb9a48bdacfe4/extendr-api/src/lib.rs#L815-L864

That's cool! You can make that an issue for a new PR or something. I'm not adding runtime tests in this PR.
JosiahParry: I'll adapt the rust tests into the extendrtests integration and push to this branch
JosiahParry: Alright! I think this is in a place where it can be merged now once the next pass of CI is all green. 

Integration tests have been added at https://github.com/extendr/extendr/pull/723/files#diff-bf77ed62590e2a1349dae79b507ae6219c1c2d8e7e2f6c3b6dff0473c0133e49.


## Follow ups 

This PR has illuminated that `IntoDataFrameRow` is not implemented for `Robj` which means extendr impls cannot be in a `Dataframe<T>` . This is covered by https://github.com/extendr/extendr/issues/727

Additionally, `Dataframe<T>` can be used as a function argument parameter, however, it will not check `T` https://github.com/extendr/extendr/issues/729



Patch:
diff --git a/extendr-api/src/wrapper/dataframe.rs b/extendr-api/src/wrapper/dataframe.rs
index 482417632..35a314bd5 100644
--- a/extendr-api/src/wrapper/dataframe.rs
+++ b/extendr-api/src/wrapper/dataframe.rs
@@ -4,24 +4,47 @@ pub trait IntoDataFrameRow<T> {
     fn into_dataframe(self) -> Result<Dataframe<T>>;
 }
 
+/// A representation of a typed `data.frame`
+///
+/// A `data.frame` can be created from Rust by using the [`IntoDataFrameRow`] trait
+/// which can be derived for a single `struct` that represents a single row.
+/// The type of the row is captured by the marker `T`.
+///
+/// Note that at present, you can create a `Dataframe<T>` but you cannot extract
+/// `T` from the object. `<T>` is purely a marker that indicates the struct that
+/// was used to create its rows.
+///
+/// As a result, using `Dataframe<T>` as a function argument _will not_ perform
+/// any type checking on the type.
 #[derive(PartialEq, Clone)]
 pub struct Dataframe<T> {
     pub(crate) robj: Robj,
-    marker: std::marker::PhantomData<T>,
+    _marker: std::marker::PhantomData<T>,
+}
+
+impl<T> From<Dataframe<T>> for Robj {
+    fn from(value: Dataframe<T>) -> Self {
+        value.robj
+    }
+}
+
+impl<T> FromRobj<'_> for Dataframe<T> {
+    fn from_robj(robj: &Robj) -> std::result::Result<Self, &'static str> {
+        robj.try_into().or(Err("expected a `data.frame`"))
+    }
 }
 
 impl<T> std::convert::TryFrom<&Robj> for Dataframe<T> {
     type Error = Error;
     fn try_from(robj: &Robj) -> Result<Self> {
         // TODO: check type using derived trait.
-        if robj.is_list() && robj.inherits("data.frame") {
-            Ok(Dataframe {
-                robj: robj.clone(),
-                marker: std::marker::PhantomData,
-            })
-        } else {
-            Err(Error::ExpectedDataframe(robj.clone()))
+        if !(robj.is_list() && robj.inherits("data.frame")) {
+            return Err(Error::ExpectedDataframe(robj.clone()));
         }
+        Ok(Dataframe {
+            robj: robj.clone(),
+            _marker: std::marker::PhantomData,
+        })
     }
 }
 
@@ -62,9 +85,3 @@ where
         )
     }
 }
-
-impl<T> IntoRobj for Dataframe<T> {
-    fn into_robj(self) -> Robj {
-        self.robj
-    }
-}


Test patch:
diff --git a/extendr-api/tests/dataframe_tests.rs b/extendr-api/tests/dataframe_tests.rs
index 00c4eeedd..c52f50aed 100644
--- a/extendr-api/tests/dataframe_tests.rs
+++ b/extendr-api/tests/dataframe_tests.rs
@@ -51,3 +51,64 @@ fn test_into_robj_dataframe() {
 
     }
 }
+
+#[derive(IntoDataFrameRow)]
+struct Row {
+    name: u32,
+}
+
+#[extendr]
+fn dataframe_conversion(_data_frame: Dataframe<Row>) -> Robj {
+    vec![Row { name: 42 }].into_dataframe().unwrap().into_robj()
+}
+
+#[extendr(use_try_from = true)]
+fn dataframe_conversion_try_from(_data_frame: Dataframe<Row>) -> Robj {
+    vec![Row { name: 42 }].into_dataframe().unwrap().into_robj()
+}
+
+#[extendr]
+fn return_dataframe(_data_frame: Dataframe<Row>) -> Dataframe<Row> {
+    vec![Row { name: 42 }].into_dataframe().unwrap()
+}
+
+#[extendr(use_try_from = true)]
+fn return_dataframe_try_from(_data_frame: Dataframe<Row>) -> Dataframe<Row> {
+    vec![Row { name: 42 }].into_dataframe().unwrap()
+}
+
+#[test]
+fn test_storing_external_ptr_as_row() {
+    struct Row {
+        _id: u32,
+    }
+
+    #[extendr]
+    impl Row {}
+
+    #[extendr]
+    fn use_dataframe_exptr(data_frame: Dataframe<Row>) -> Dataframe<Row> {
+        data_frame
+    }
+}
+
+#[test]
+fn test_dataframe_row_and_externalptr() {
+    #[derive(IntoDataFrameRow)]
+    struct RowAndExptr {
+        id: u32,
+    }
+
+    #[extendr]
+    impl RowAndExptr {}
+
+    #[extendr]
+    fn use_dataframe_exptr2(data_frame: Dataframe<RowAndExptr>) -> Dataframe<RowAndExptr> {
+        data_frame
+    }
+
+    #[extendr(use_try_from = true)]
+    fn use_dataframe_exptr3(data_frame: Dataframe<RowAndExptr>) -> Dataframe<RowAndExptr> {
+        data_frame
+    }
+}
diff --git a/tests/extendrtests/R/extendr-wrappers.R b/tests/extendrtests/R/extendr-wrappers.R
index fb62038e1..9940ee815 100644
--- a/tests/extendrtests/R/extendr-wrappers.R
+++ b/tests/extendrtests/R/extendr-wrappers.R
@@ -76,9 +76,33 @@ add_5_if_not_null <- function(x) .Call(wrap__add_5_if_not_null, x)
 #' @export
 my_device <- function(welcome_message) invisible(.Call(wrap__my_device, welcome_message))
 
-#' Return string `"Hello world!"` to R.
-#' @export
-hello_submodule <- function() .Call(wrap__hello_submodule)
+new_usize <- function(robj) .Call(wrap__new_usize, robj)
+
+tst_altstring <- function() .Call(wrap__tst_altstring)
+
+tst_altinteger <- function() .Call(wrap__tst_altinteger)
+
+test_derive_into_dataframe <- function() .Call(wrap__test_derive_into_dataframe)
+
+test_into_robj_dataframe <- function() .Call(wrap__test_into_robj_dataframe)
+
+leak_implicit_strings <- function(x) .Call(wrap__leak_implicit_strings, x)
+
+leak_implicit_doubles <- function(x) .Call(wrap__leak_implicit_doubles, x)
+
+leak_arg2_try_implicit_strings <- function(`_y`, x) .Call(wrap__leak_arg2_try_implicit_strings, `_y`, x)
+
+leak_arg2_try_implicit_doubles <- function(`_y`, x) .Call(wrap__leak_arg2_try_implicit_doubles, `_y`, x)
+
+leak_unwrap_strings <- function(x) .Call(wrap__leak_unwrap_strings, x)
+
+leak_unwrap_doubles <- function(x) .Call(wrap__leak_unwrap_doubles, x)
+
+leak_positive_control <- function(x) invisible(.Call(wrap__leak_positive_control, x))
+
+leak_negative_control <- function(x) invisible(.Call(wrap__leak_negative_control, x))
+
+type_aware_sum <- function(input) .Call(wrap__type_aware_sum, input)
 
 #' Calculate Euclidean distance matrix
 #' Test case adopted from https://github.com/mikemahoney218/examplerust/blob/23d21b1ced4e24b7a7c00dd36290114dc1bbd113/src/rust/src/lib.rs#L5
@@ -86,8 +110,6 @@ hello_submodule <- function() .Call(wrap__hello_submodule)
 #' @export
 euclidean_dist <- function(a) .Call(wrap__euclidean_dist, a)
 
-type_aware_sum <- function(input) .Call(wrap__type_aware_sum, input)
-
 #' Test raw identifiers (`r#`) in function arguments are parsed correctly.
 #' See [Issue #582](https://github.com/extendr/extendr/issues/528) for details.
 #' @param type : i32 or `NULL`
@@ -105,27 +127,9 @@ true <- function() .Call(wrap__true)
 #' @export
 false <- function(type) .Call(wrap__false, type)
 
-leak_implicit_strings <- function(x) .Call(wrap__leak_implicit_strings, x)
-
-leak_implicit_doubles <- function(x) .Call(wrap__leak_implicit_doubles, x)
-
-leak_arg2_try_implicit_strings <- function(`_y`, x) .Call(wrap__leak_arg2_try_implicit_strings, `_y`, x)
-
-leak_arg2_try_implicit_doubles <- function(`_y`, x) .Call(wrap__leak_arg2_try_implicit_doubles, `_y`, x)
-
-leak_unwrap_strings <- function(x) .Call(wrap__leak_unwrap_strings, x)
-
-leak_unwrap_doubles <- function(x) .Call(wrap__leak_unwrap_doubles, x)
-
-leak_positive_control <- function(x) invisible(.Call(wrap__leak_positive_control, x))
-
-leak_negative_control <- function(x) invisible(.Call(wrap__leak_negative_control, x))
-
-new_usize <- function(robj) .Call(wrap__new_usize, robj)
-
-tst_altstring <- function() .Call(wrap__tst_altstring)
-
-tst_altinteger <- function() .Call(wrap__tst_altinteger)
+#' Return string `"Hello world!"` to R.
+#' @export
+hello_submodule <- function() .Call(wrap__hello_submodule)
 
 #' Class for testing (exported)
 #' @examples
diff --git a/tests/extendrtests/src/rust/src/dataframe.rs b/tests/extendrtests/src/rust/src/dataframe.rs
new file mode 100644
index 000000000..fefacfc74
--- /dev/null
+++ b/tests/extendrtests/src/rust/src/dataframe.rs
@@ -0,0 +1,75 @@
+use extendr_api::prelude::*;
+
+#[derive(Debug, IntoDataFrameRow)]
+struct MyStruct {
+    x: Rint,
+    y: Rstr,
+}
+
+#[extendr]
+fn test_derive_into_dataframe() -> Dataframe<MyStruct> {
+    let v = vec![
+        MyStruct {
+            x: 0.into(),
+            y: "abc".into(),
+        },
+        MyStruct {
+            x: 1.into(),
+            y: "xyz".into(),
+        },
+    ];
+    v.into_dataframe().unwrap()
+}
+
+#[extendr]
+fn test_into_robj_dataframe() -> Robj {
+    let v = vec![
+        MyStruct {
+            x: 0.into(),
+            y: "abc".into(),
+        },
+        MyStruct {
+            x: 1.into(),
+            y: "xyz".into(),
+        },
+    ];
+    v.into_dataframe().unwrap().into_robj()
+}
+
+// Not possible today
+// https://github.com/extendr/extendr/issues/727
+// #[derive(Debug, IntoDataFrameRow)]
+// struct Val;
+
+// #[extendr]
+// impl Val {
+//     fn new() -> Self {
+//         Val {}
+//     }
+// }
+// #[derive(IntoDataFrameRow)]
+// struct Row {
+//     v: Val,
+// }
+// #[extendr]
+// fn test_use_externalptr() -> Robj {
+//     vec![Row { v: Val::new() }]
+//         .into_dataframe()
+//         .unwrap()
+//         .into_robj()
+// }
+
+// This isn't relavent right now
+// thats because issue https://github.com/extendr/extendr/issues/714
+// is not solved we would need an iterator for Dataframe<T> for it to
+// actually be useful
+// #[extendr(use_try_from = true)]
+// fn dataframe_conversion_try_from(_data_frame: Dataframe<Row>) -> Robj {
+//     vec![Row { name: 42 }].into_dataframe().unwrap().into_robj()
+// }
+
+extendr_module! {
+    mod dataframe;
+    fn test_derive_into_dataframe;
+    fn test_into_robj_dataframe;
+}
diff --git a/tests/extendrtests/src/rust/src/lib.rs b/tests/extendrtests/src/rust/src/lib.rs
index ae7e26dcc..5ea609d3d 100644
--- a/tests/extendrtests/src/rust/src/lib.rs
+++ b/tests/extendrtests/src/rust/src/lib.rs
@@ -1,18 +1,13 @@
 use extendr_api::{graphics::*, prelude::*};
 
-mod submodule;
-
-mod optional_ndarray;
-
+mod altrep;
+mod dataframe;
 mod graphic_device;
-
+mod memory_leaks;
 mod optional_either;
-
+mod optional_ndarray;
 mod raw_identifiers;
-
-mod memory_leaks;
-
-mod altrep;
+mod submodule;
 
 // Return string `"Hello world!"` to R.
 #[extendr]
@@ -360,10 +355,12 @@ extendr_module! {
 
     fn my_device;
 
-    use submodule;
-    use optional_ndarray;
+    use altrep;
+    use dataframe;
+    use memory_leaks;
     use optional_either;
+    use optional_ndarray;
     use raw_identifiers;
-    use memory_leaks;
-    use altrep;
+    use submodule;
+
 }
diff --git a/tests/extendrtests/tests/testthat/_snaps/macro-snapshot.md b/tests/extendrtests/tests/testthat/_snaps/macro-snapshot.md
index 15933f78f..9e6df0f69 100644
--- a/tests/extendrtests/tests/testthat/_snaps/macro-snapshot.md
+++ b/tests/extendrtests/tests/testthat/_snaps/macro-snapshot.md
@@ -9,23 +9,126 @@
       #[macro_use]
       extern crate std;
       use extendr_api::{graphics::*, prelude::*};
-      mod submodule {
+      mod altrep {
           use extendr_api::prelude::*;
-          /// Return string `"Hello world!"` to R.
-          /// @export
-          fn hello_submodule() -> &'static str {
-              "Hello World!"
+          pub struct VecUsize(pub Vec<Option<usize>>);
+          #[automatically_derived]
+          impl ::core::fmt::Debug for VecUsize {
+              #[inline]
+              fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+                  ::core::fmt::Formatter::debug_tuple_field1_finish(f, "VecUsize", &&self.0)
+              }
+          }
+          #[automatically_derived]
+          impl ::core::clone::Clone for VecUsize {
+              #[inline]
+              fn clone(&self) -> VecUsize {
+                  VecUsize(::core::clone::Clone::clone(&self.0))
+              }
+          }
+          impl AltrepImpl for VecUsize {
+              fn length(&self) -> usize {
+                  self.0.len()
+              }
+          }
+          #[cfg(use_r_altlist)]
+          impl VecUsize {}
+          impl<'a> extendr_api::FromRobj<'a> for &VecUsize {
+              fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
+                  if robj.check_external_ptr_type::<VecUsize>() {
+                      #[allow(clippy::transmute_ptr_to_ref)]
+                      Ok(unsafe { std::mem::transmute(robj.external_ptr_addr::<VecUsize>()) })
+                  } else {
+                      Err("expected VecUsize")
+                  }
+              }
+          }
+          impl<'a> extendr_api::FromRobj<'a> for &mut VecUsize {
+              fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
+                  if robj.check_external_ptr_type::<VecUsize>() {
+                      #[allow(clippy::transmute_ptr_to_ref)]
+                      Ok(unsafe { std::mem::transmute(robj.external_ptr_addr::<VecUsize>()) })
+                  } else {
+                      Err("expected VecUsize")
+                  }
+              }
+          }
+          impl From<VecUsize> for Robj {
+              fn from(value: VecUsize) -> Self {
+                  unsafe {
+                      let ptr = Box::into_raw(Box::new(value));
+                      let mut res = Robj::make_external_ptr(ptr, Robj::from(()));
+                      res.set_attrib(class_symbol(), "VecUsize").unwrap();
+                      res.register_c_finalizer(Some(__finalize__VecUsize));
+                      res
+                  }
+              }
+          }
+          impl<'a> From<&'a VecUsize> for Robj {
+              fn from(value: &'a VecUsize) -> Self {
+                  unsafe {
+                      let ptr = Box::into_raw(Box::new(value));
+                      let mut res = Robj::make_external_ptr(ptr, Robj::from(()));
+                      res.set_attrib(class_symbol(), "VecUsize").unwrap();
+                      res.register_c_finalizer(Some(__finalize__VecUsize));
+                      res
+                  }
+              }
+          }
+          extern "C" fn __finalize__VecUsize(sexp: extendr_api::SEXP) {
+              unsafe {
+                  let robj = extendr_api::robj::Robj::from_sexp(sexp);
+                  if robj.check_external_ptr_type::<VecUsize>() {
+                      let ptr = robj.external_ptr_addr::<VecUsize>();
+                      drop(Box::from_raw(ptr));
+                  }
+              }
+          }
+          #[allow(non_snake_case)]
+          fn meta__VecUsize(impls: &mut Vec<extendr_api::metadata::Impl>) {
+              let mut methods = Vec::new();
+              impls
+                  .push(extendr_api::metadata::Impl {
+                      doc: "",
+                      name: "VecUsize",
+                      methods,
+                  });
+          }
+          #[cfg(use_r_altlist)]
+          impl AltListImpl for VecUsize {
+              fn elt(&self, index: usize) -> Robj {
+                  self.into_robj()
+              }
+          }
+          #[cfg(use_r_altlist)]
+          fn new_usize(robj: Integers) -> Altrep {
+              let x = robj
+                  .iter()
+                  .map(|x| match &x {
+                      _ if x.is_na() => None,
+                      _ if x.inner() < 0 => None,
+                      _ => Some(x.inner() as usize),
+                  })
+                  .collect();
+              let obj = VecUsize(x);
+              let class = Altrep::make_altlist_class::<VecUsize>("li", "mypkg");
+              Altrep::from_state_and_class(obj, class, false)
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__hello_submodule() -> extendr_api::SEXP {
+          pub extern "C" fn wrap__new_usize(robj: extendr_api::SEXP) -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
+                  let _robj_robj = extendr_api::robj::Robj::from_sexp(robj);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(extendr_api::Robj::from(hello_submodule()))
+                      Ok(
+                          extendr_api::Robj::from(
+                              new_usize(<Integers>::from_robj(&_robj_robj)?),
+                          ),
+                      )
                   })
               };
               match wrap_result_state {
@@ -41,7 +144,7 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "hello_submodule"),
+                              format_args!("user function panicked: {0}", "new_usize"),
                           );
                           res
                       };
@@ -69,106 +172,82 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__hello_submodule(metadata: &mut Vec<extendr_api::metadata::Func>) {
-              let mut args = ::alloc::vec::Vec::new();
+          fn meta__new_usize(metadata: &mut Vec<extendr_api::metadata::Func>) {
+              let mut args = <[_]>::into_vec(
+                  #[rustc_box]
+                  ::alloc::boxed::Box::new([
+                      extendr_api::metadata::Arg {
+                          name: "robj",
+                          arg_type: "Integers",
+                          default: None,
+                      },
+                  ]),
+              );
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: " Return string `\"Hello world!\"` to R.\n @export",
-                      rust_name: "hello_submodule",
-                      r_name: "hello_submodule",
-                      mod_name: "hello_submodule",
+                      doc: "",
+                      rust_name: "new_usize",
+                      r_name: "new_usize",
+                      mod_name: "new_usize",
                       args: args,
-                      return_type: "str",
-                      func_ptr: wrap__hello_submodule as *const u8,
+                      return_type: "Altrep",
+                      func_ptr: wrap__new_usize as *const u8,
                       hidden: false,
                   })
           }
-          struct MySubmoduleClass {
-              a: i32,
-          }
-          #[automatically_derived]
-          impl ::core::default::Default for MySubmoduleClass {
-              #[inline]
-              fn default() -> MySubmoduleClass {
-                  MySubmoduleClass {
-                      a: ::core::default::Default::default(),
-                  }
-              }
+          struct StringInts {
+              len: usize,
           }
           #[automatically_derived]
-          impl ::core::fmt::Debug for MySubmoduleClass {
+          impl ::core::fmt::Debug for StringInts {
               #[inline]
               fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
                   ::core::fmt::Formatter::debug_struct_field1_finish(
                       f,
-                      "MySubmoduleClass",
-                      "a",
-                      &&self.a,
+                      "StringInts",
+                      "len",
+                      &&self.len,
                   )
               }
           }
           #[automatically_derived]
-          impl ::core::clone::Clone for MySubmoduleClass {
+          impl ::core::clone::Clone for StringInts {
               #[inline]
-              fn clone(&self) -> MySubmoduleClass {
-                  let _: ::core::clone::AssertParamIsClone<i32>;
-                  *self
+              fn clone(&self) -> StringInts {
+                  StringInts {
+                      len: ::core::clone::Clone::clone(&self.len),
+                  }
               }
           }
-          #[automatically_derived]
-          impl ::core::marker::Copy for MySubmoduleClass {}
-          /// Class for testing (exported)
-          /// @examples
-          /// x <- MySubmoduleClass$new()
-          /// x$a()
-          /// x$set_a(10)
-          /// x$a()
-          /// @export
-          impl MySubmoduleClass {
-              /// Method for making a new object.
-              fn new() -> Self {
-                  Self { a: 0 }
-              }
-              /// Method for setting stuff.
-              /// @param x a number
-              fn set_a(&mut self, x: i32) {
-                  self.a = x;
-              }
-              /// Method for getting stuff.
-              fn a(&self) -> i32 {
-                  self.a
-              }
-              /// Method for getting one's (by way of a copy) self.
-              fn me_owned(&self) -> Self {
-                  *self
-              }
-              /// Method for getting one's (ref) self.
-              fn me_ref(&self) -> &Self {
-                  self
-              }
-              /// Method for getting one's (ref mut) self.
-              fn me_mut(&mut self) -> &mut Self {
-                  self
-              }
-              /// Method for getting one's ref (explicit) self.
-              fn me_explicit_ref(&self) -> &MySubmoduleClass {
-                  self
+          impl AltrepImpl for StringInts {
+              fn length(&self) -> usize {
+                  self.len as usize
               }
-              /// Method for getting one's ref mut (explicit) self.
-              fn me_explicit_mut(&mut self) -> &mut MySubmoduleClass {
-                  self
+          }
+          impl AltStringImpl for StringInts {
+              fn elt(&self, index: usize) -> Rstr {
+                  {
+                      let res = ::alloc::fmt::format(format_args!("{0}", index));
+                      res
+                  }
+                      .into()
               }
           }
+          fn tst_altstring() -> Altrep {
+              let mystate = StringInts { len: 10 };
+              let class = Altrep::make_altstring_class::<StringInts>("si", "mypkg");
+              Altrep::from_state_and_class(mystate, class, false)
+          }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__MySubmoduleClass__new() -> extendr_api::SEXP {
+          pub extern "C" fn wrap__tst_altstring() -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(extendr_api::Robj::from(<MySubmoduleClass>::new()))
+                      Ok(extendr_api::Robj::from(tst_altstring()))
                   })
               };
               match wrap_result_state {
@@ -184,7 +263,7 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "new"),
+                              format_args!("user function panicked: {0}", "tst_altstring"),
                           );
                           res
                       };
@@ -212,42 +291,90 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__MySubmoduleClass__new(metadata: &mut Vec<extendr_api::metadata::Func>) {
+          fn meta__tst_altstring(metadata: &mut Vec<extendr_api::metadata::Func>) {
               let mut args = ::alloc::vec::Vec::new();
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: " Method for making a new object.",
-                      rust_name: "new",
-                      r_name: "new",
-                      mod_name: "new",
+                      doc: "",
+                      rust_name: "tst_altstring",
+                      r_name: "tst_altstring",
+                      mod_name: "tst_altstring",
                       args: args,
-                      return_type: "Self",
-                      func_ptr: wrap__MySubmoduleClass__new as *const u8,
+                      return_type: "Altrep",
+                      func_ptr: wrap__tst_altstring as *const u8,
                       hidden: false,
                   })
           }
-          #[no_mangle]
-          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__MySubmoduleClass__set_a(
-              _self: extendr_api::SEXP,
-              x: extendr_api::SEXP,
-          ) -> extendr_api::SEXP {
+          struct MyCompactIntRange {
+              start: i32,
+              len: i32,
+              step: i32,
+              missing_index: usize,
+          }
+          #[automatically_derived]
+          impl ::core::fmt::Debug for MyCompactIntRange {
+              #[inline]
+              fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+                  ::core::fmt::Formatter::debug_struct_field4_finish(
+                      f,
+                      "MyCompactIntRange",
+                      "start",
+                      &self.start,
+                      "len",
+                      &self.len,
+                      "step",
+                      &self.step,
+                      "missing_index",
+                      &&self.missing_index,
+                  )
+              }
+          }
+          #[automatically_derived]
+          impl ::core::clone::Clone for MyCompactIntRange {
+              #[inline]
+              fn clone(&self) -> MyCompactIntRange {
+                  MyCompactIntRange {
+                      start: ::core::clone::Clone::clone(&self.start),
+                      len: ::core::clone::Clone::clone(&self.len),
+                      step: ::core::clone::Clone::clone(&self.step),
+                      missing_index: ::core::clone::Clone::clone(&self.missing_index),
+                  }
+              }
+          }
+          impl AltrepImpl for MyCompactIntRange {
+              fn length(&self) -> usize {
+                  self.len as usize
+              }
+          }
+          impl AltIntegerImpl for MyCompactIntRange {
+              fn elt(&self, index: usize) -> Rint {
+                  if index == self.missing_index {
+                      Rint::na()
+                  } else {
+                      Rint::new(self.start + self.step * index as i32)
+                  }
+              }
+          }
+          fn tst_altinteger() -> Altrep {
+              let mystate = MyCompactIntRange {
+                  start: 0,
+                  len: 10,
+                  step: 1,
+                  missing_index: usize::MAX,
+              };
+              let class = Altrep::make_altinteger_class::<MyCompactIntRange>("cir", "mypkg");
+              Altrep::from_state_and_class(mystate, class.clone(), false)
+          }
+          #[no_mangle]
+          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
+          pub extern "C" fn wrap__tst_altinteger() -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let mut _self_robj = extendr_api::robj::Robj::from_sexp(_self);
-                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(
-                          extendr_api::Robj::from(
-                              extendr_api::unwrap_or_throw(
-                                      <&mut MySubmoduleClass>::from_robj(&_self_robj),
-                                  )
-                                  .set_a(<i32>::from_robj(&_x_robj)?),
-                          ),
-                      )
+                      Ok(extendr_api::Robj::from(tst_altinteger()))
                   })
               };
               match wrap_result_state {
@@ -263,7 +390,7 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "set_a"),
+                              format_args!("user function panicked: {0}", "tst_altinteger"),
                           );
                           res
                       };
@@ -291,54 +418,195 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__MySubmoduleClass__set_a(metadata: &mut Vec<extendr_api::metadata::Func>) {
-              let mut args = <[_]>::into_vec(
-                  #[rustc_box]
-                  ::alloc::boxed::Box::new([
-                      extendr_api::metadata::Arg {
-                          name: "self",
-                          arg_type: "MySubmoduleClass",
-                          default: None,
-                      },
-                      extendr_api::metadata::Arg {
-                          name: "x",
-                          arg_type: "i32",
-                          default: None,
-                      },
-                  ]),
-              );
+          fn meta__tst_altinteger(metadata: &mut Vec<extendr_api::metadata::Func>) {
+              let mut args = ::alloc::vec::Vec::new();
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: " Method for setting stuff.\n @param x a number",
-                      rust_name: "set_a",
-                      r_name: "set_a",
-                      mod_name: "set_a",
+                      doc: "",
+                      rust_name: "tst_altinteger",
+                      r_name: "tst_altinteger",
+                      mod_name: "tst_altinteger",
                       args: args,
-                      return_type: "()",
-                      func_ptr: wrap__MySubmoduleClass__set_a as *const u8,
+                      return_type: "Altrep",
+                      func_ptr: wrap__tst_altinteger as *const u8,
                       hidden: false,
                   })
           }
           #[no_mangle]
+          #[allow(non_snake_case)]
+          pub fn get_altrep_metadata() -> extendr_api::metadata::Metadata {
+              let mut functions = Vec::new();
+              let mut impls = Vec::new();
+              meta__new_usize(&mut functions);
+              meta__tst_altstring(&mut functions);
+              meta__tst_altinteger(&mut functions);
+              functions
+                  .push(extendr_api::metadata::Func {
+                      doc: "Metadata access function.",
+                      rust_name: "get_altrep_metadata",
+                      mod_name: "get_altrep_metadata",
+                      r_name: "get_altrep_metadata",
+                      args: Vec::new(),
+                      return_type: "Metadata",
+                      func_ptr: wrap__get_altrep_metadata as *const u8,
+                      hidden: true,
+                  });
+              functions
+                  .push(extendr_api::metadata::Func {
+                      doc: "Wrapper generator.",
+                      rust_name: "make_altrep_wrappers",
+                      mod_name: "make_altrep_wrappers",
+                      r_name: "make_altrep_wrappers",
+                      args: <[_]>::into_vec(
+                          #[rustc_box]
+                          ::alloc::boxed::Box::new([
+                              extendr_api::metadata::Arg {
+                                  name: "use_symbols",
+                                  arg_type: "bool",
+                                  default: None,
+                              },
+                              extendr_api::metadata::Arg {
+                                  name: "package_name",
+                                  arg_type: "&str",
+                                  default: None,
+                              },
+                          ]),
+                      ),
+                      return_type: "String",
+                      func_ptr: wrap__make_altrep_wrappers as *const u8,
+                      hidden: true,
+                  });
+              extendr_api::metadata::Metadata {
+                  name: "altrep",
+                  functions,
+                  impls,
+              }
+          }
+          #[no_mangle]
+          #[allow(non_snake_case)]
+          pub extern "C" fn wrap__get_altrep_metadata() -> extendr_api::SEXP {
+              use extendr_api::GetSexp;
+              unsafe { extendr_api::Robj::from(get_altrep_metadata()).get() }
+          }
+          #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__MySubmoduleClass__a(
-              _self: extendr_api::SEXP,
+          pub extern "C" fn wrap__make_altrep_wrappers(
+              use_symbols_sexp: extendr_api::SEXP,
+              package_name_sexp: extendr_api::SEXP,
           ) -> extendr_api::SEXP {
+              unsafe {
+                  use extendr_api::robj::*;
+                  use extendr_api::GetSexp;
+                  let robj = Robj::from_sexp(use_symbols_sexp);
+                  let use_symbols: bool = <bool>::from_robj(&robj).unwrap();
+                  let robj = Robj::from_sexp(package_name_sexp);
+                  let package_name: &str = <&str>::from_robj(&robj).unwrap();
+                  extendr_api::Robj::from(
+                          get_altrep_metadata()
+                              .make_r_wrappers(use_symbols, package_name)
+                              .unwrap(),
+                      )
+                      .get()
+              }
+          }
+          #[no_mangle]
+          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
+          pub extern "C" fn R_init_altrep_extendr(info: *mut extendr_api::DllInfo) {
+              unsafe { extendr_api::register_call_methods(info, get_altrep_metadata()) };
+          }
+      }
+      mod dataframe {
+          use extendr_api::prelude::*;
+          struct MyStruct {
+              x: Rint,
+              y: Rstr,
+          }
+          #[automatically_derived]
+          impl ::core::fmt::Debug for MyStruct {
+              #[inline]
+              fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+                  ::core::fmt::Formatter::debug_struct_field2_finish(
+                      f,
+                      "MyStruct",
+                      "x",
+                      &self.x,
+                      "y",
+                      &&self.y,
+                  )
+              }
+          }
+          impl IntoDataFrameRow<MyStruct> for Vec<MyStruct> {
+              fn into_dataframe(self) -> Result<Dataframe<MyStruct>> {
+                  let mut x = Vec::with_capacity(self.len());
+                  let mut y = Vec::with_capacity(self.len());
+                  for val in self {
+                      x.push(val.x);
+                      y.push(val.y);
+                  }
+                  let caller = eval_string("data.frame")?;
+                  let res = caller
+                      .call(
+                          Pairlist::from_pairs(
+                              &[
+                                  ("x", extendr_api::robj::Robj::from(x)),
+                                  ("y", extendr_api::robj::Robj::from(y)),
+                              ],
+                          ),
+                      )?;
+                  res.try_into()
+              }
+          }
+          impl<I> IntoDataFrameRow<MyStruct> for (I,)
+          where
+              I: ExactSizeIterator<Item = MyStruct>,
+          {
+              /// Thanks to RFC 2451, we need to wrap a generic iterator in a tuple!
+              fn into_dataframe(self) -> Result<Dataframe<MyStruct>> {
+                  let mut x = Vec::with_capacity(self.0.len());
+                  let mut y = Vec::with_capacity(self.0.len());
+                  for val in self.0 {
+                      x.push(val.x);
+                      y.push(val.y);
+                  }
+                  let caller = eval_string("data.frame")?;
+                  let res = caller
+                      .call(
+                          Pairlist::from_pairs(
+                              &[
+                                  ("x", extendr_api::robj::Robj::from(x)),
+                                  ("y", extendr_api::robj::Robj::from(y)),
+                              ],
+                          ),
+                      )?;
+                  res.try_into()
+              }
+          }
+          fn test_derive_into_dataframe() -> Dataframe<MyStruct> {
+              let v = <[_]>::into_vec(
+                  #[rustc_box]
+                  ::alloc::boxed::Box::new([
+                      MyStruct {
+                          x: 0.into(),
+                          y: "abc".into(),
+                      },
+                      MyStruct {
+                          x: 1.into(),
+                          y: "xyz".into(),
+                      },
+                  ]),
+              );
+              v.into_dataframe().unwrap()
+          }
+          #[no_mangle]
+          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
+          pub extern "C" fn wrap__test_derive_into_dataframe() -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let mut _self_robj = extendr_api::robj::Robj::from_sexp(_self);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(
-                          extendr_api::Robj::from(
-                              extendr_api::unwrap_or_throw(
-                                      <&MySubmoduleClass>::from_robj(&_self_robj),
-                                  )
-                                  .a(),
-                          ),
-                      )
+                      Ok(extendr_api::Robj::from(test_derive_into_dataframe()))
                   })
               };
               match wrap_result_state {
@@ -354,7 +622,10 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "a"),
+                              format_args!(
+                                  "user function panicked: {0}",
+                                  "test_derive_into_dataframe",
+                              ),
                           );
                           res
                       };
@@ -382,49 +653,48 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__MySubmoduleClass__a(metadata: &mut Vec<extendr_api::metadata::Func>) {
-              let mut args = <[_]>::into_vec(
-                  #[rustc_box]
-                  ::alloc::boxed::Box::new([
-                      extendr_api::metadata::Arg {
-                          name: "self",
-                          arg_type: "MySubmoduleClass",
-                          default: None,
-                      },
-                  ]),
-              );
+          fn meta__test_derive_into_dataframe(
+              metadata: &mut Vec<extendr_api::metadata::Func>,
+          ) {
+              let mut args = ::alloc::vec::Vec::new();
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: " Method for getting stuff.",
-                      rust_name: "a",
-                      r_name: "a",
-                      mod_name: "a",
+                      doc: "",
+                      rust_name: "test_derive_into_dataframe",
+                      r_name: "test_derive_into_dataframe",
+                      mod_name: "test_derive_into_dataframe",
                       args: args,
-                      return_type: "i32",
-                      func_ptr: wrap__MySubmoduleClass__a as *const u8,
+                      return_type: "Dataframe",
+                      func_ptr: wrap__test_derive_into_dataframe as *const u8,
                       hidden: false,
                   })
           }
-          #[no_mangle]
-          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__MySubmoduleClass__me_owned(
-              _self: extendr_api::SEXP,
-          ) -> extendr_api::SEXP {
-              use extendr_api::robj::*;
+          fn test_into_robj_dataframe() -> Robj {
+              let v = <[_]>::into_vec(
+                  #[rustc_box]
+                  ::alloc::boxed::Box::new([
+                      MyStruct {
+                          x: 0.into(),
+                          y: "abc".into(),
+                      },
+                      MyStruct {
+                          x: 1.into(),
+                          y: "xyz".into(),
+                      },
+                  ]),
+              );
+              v.into_dataframe().unwrap().into_robj()
+          }
+          #[no_mangle]
+          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
+          pub extern "C" fn wrap__test_into_robj_dataframe() -> extendr_api::SEXP {
+              use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let mut _self_robj = extendr_api::robj::Robj::from_sexp(_self);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(
-                          extendr_api::Robj::from(
-                              extendr_api::unwrap_or_throw(
-                                      <&MySubmoduleClass>::from_robj(&_self_robj),
-                                  )
-                                  .me_owned(),
-                          ),
-                      )
+                      Ok(extendr_api::Robj::from(test_into_robj_dataframe()))
                   })
               };
               match wrap_result_state {
@@ -440,7 +710,10 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "me_owned"),
+                              format_args!(
+                                  "user function panicked: {0}",
+                                  "test_into_robj_dataframe",
+                              ),
                           );
                           res
                       };
@@ -468,48 +741,149 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__MySubmoduleClass__me_owned(
-              metadata: &mut Vec<extendr_api::metadata::Func>,
-          ) {
-              let mut args = <[_]>::into_vec(
-                  #[rustc_box]
-                  ::alloc::boxed::Box::new([
-                      extendr_api::metadata::Arg {
-                          name: "self",
-                          arg_type: "MySubmoduleClass",
-                          default: None,
-                      },
-                  ]),
-              );
+          fn meta__test_into_robj_dataframe(metadata: &mut Vec<extendr_api::metadata::Func>) {
+              let mut args = ::alloc::vec::Vec::new();
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: " Method for getting one's (by way of a copy) self.",
-                      rust_name: "me_owned",
-                      r_name: "me_owned",
-                      mod_name: "me_owned",
+                      doc: "",
+                      rust_name: "test_into_robj_dataframe",
+                      r_name: "test_into_robj_dataframe",
+                      mod_name: "test_into_robj_dataframe",
                       args: args,
-                      return_type: "Self",
-                      func_ptr: wrap__MySubmoduleClass__me_owned as *const u8,
+                      return_type: "Robj",
+                      func_ptr: wrap__test_into_robj_dataframe as *const u8,
                       hidden: false,
                   })
           }
           #[no_mangle]
+          #[allow(non_snake_case)]
+          pub fn get_dataframe_metadata() -> extendr_api::metadata::Metadata {
+              let mut functions = Vec::new();
+              let mut impls = Vec::new();
+              meta__test_derive_into_dataframe(&mut functions);
+              meta__test_into_robj_dataframe(&mut functions);
+              functions
+                  .push(extendr_api::metadata::Func {
+                      doc: "Metadata access function.",
+                      rust_name: "get_dataframe_metadata",
+                      mod_name: "get_dataframe_metadata",
+                      r_name: "get_dataframe_metadata",
+                      args: Vec::new(),
+                      return_type: "Metadata",
+                      func_ptr: wrap__get_dataframe_metadata as *const u8,
+                      hidden: true,
+                  });
+              functions
+                  .push(extendr_api::metadata::Func {
+                      doc: "Wrapper generator.",
+                      rust_name: "make_dataframe_wrappers",
+                      mod_name: "make_dataframe_wrappers",
+                      r_name: "make_dataframe_wrappers",
+                      args: <[_]>::into_vec(
+                          #[rustc_box]
+                          ::alloc::boxed::Box::new([
+                              extendr_api::metadata::Arg {
+                                  name: "use_symbols",
+                                  arg_type: "bool",
+                                  default: None,
+                              },
+                              extendr_api::metadata::Arg {
+                                  name: "package_name",
+                                  arg_type: "&str",
+                                  default: None,
+                              },
+                          ]),
+                      ),
+                      return_type: "String",
+                      func_ptr: wrap__make_dataframe_wrappers as *const u8,
+                      hidden: true,
+                  });
+              extendr_api::metadata::Metadata {
+                  name: "dataframe",
+                  functions,
+                  impls,
+              }
+          }
+          #[no_mangle]
+          #[allow(non_snake_case)]
+          pub extern "C" fn wrap__get_dataframe_metadata() -> extendr_api::SEXP {
+              use extendr_api::GetSexp;
+              unsafe { extendr_api::Robj::from(get_dataframe_metadata()).get() }
+          }
+          #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__MySubmoduleClass__me_ref(
-              _self: extendr_api::SEXP,
+          pub extern "C" fn wrap__make_dataframe_wrappers(
+              use_symbols_sexp: extendr_api::SEXP,
+              package_name_sexp: extendr_api::SEXP,
+          ) -> extendr_api::SEXP {
+              unsafe {
+                  use extendr_api::robj::*;
+                  use extendr_api::GetSexp;
+                  let robj = Robj::from_sexp(use_symbols_sexp);
+                  let use_symbols: bool = <bool>::from_robj(&robj).unwrap();
+                  let robj = Robj::from_sexp(package_name_sexp);
+                  let package_name: &str = <&str>::from_robj(&robj).unwrap();
+                  extendr_api::Robj::from(
+                          get_dataframe_metadata()
+                              .make_r_wrappers(use_symbols, package_name)
+                              .unwrap(),
+                      )
+                      .get()
+              }
+          }
+          #[no_mangle]
+          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
+          pub extern "C" fn R_init_dataframe_extendr(info: *mut extendr_api::DllInfo) {
+              unsafe { extendr_api::register_call_methods(info, get_dataframe_metadata()) };
+          }
+      }
+      mod graphic_device {
+          use extendr_api::{graphics::*, prelude::*};
+          pub(crate) struct MyDevice<'a> {
+              pub(crate) welcome_message: &'a str,
+          }
+          impl<'a> DeviceDriver for MyDevice<'a> {
+              fn activate(&mut self, _dd: DevDesc) {
+                  let welcome_message = self.welcome_message;
+                  print_r_output({
+                      let res = ::alloc::fmt::format(
+                          format_args!("message from device: {0}", welcome_message),
+                      );
+                      res
+                  });
+                  print_r_output("\n");
+              }
+              fn close(&mut self, _dd: DevDesc) {
+                  print_r_output({
+                      let res = ::alloc::fmt::format(format_args!("good bye..."));
+                      res
+                  });
+                  print_r_output("\n");
+              }
+          }
+      }
+      mod memory_leaks {
+          use extendr_api::prelude::*;
+          fn leak_implicit_strings(x: Strings) -> String {
+              x.len().to_string()
+          }
+          #[no_mangle]
+          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
+          pub extern "C" fn wrap__leak_implicit_strings(
+              x: extendr_api::SEXP,
           ) -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let mut _self_robj = extendr_api::robj::Robj::from_sexp(_self);
+                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      let _return_ref_to_self = extendr_api::unwrap_or_throw(
-                              <&MySubmoduleClass>::from_robj(&_self_robj),
-                          )
-                          .me_ref();
-                      Ok(_self_robj)
+                      Ok(
+                          extendr_api::Robj::from(
+                              leak_implicit_strings(<Strings>::from_robj(&_x_robj)?),
+                          ),
+                      )
                   })
               };
               match wrap_result_state {
@@ -525,7 +899,10 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "me_ref"),
+                              format_args!(
+                                  "user function panicked: {0}",
+                                  "leak_implicit_strings",
+                              ),
                           );
                           res
                       };
@@ -553,46 +930,49 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__MySubmoduleClass__me_ref(metadata: &mut Vec<extendr_api::metadata::Func>) {
+          fn meta__leak_implicit_strings(metadata: &mut Vec<extendr_api::metadata::Func>) {
               let mut args = <[_]>::into_vec(
                   #[rustc_box]
                   ::alloc::boxed::Box::new([
                       extendr_api::metadata::Arg {
-                          name: "self",
-                          arg_type: "MySubmoduleClass",
+                          name: "x",
+                          arg_type: "Strings",
                           default: None,
                       },
                   ]),
               );
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: " Method for getting one's (ref) self.",
-                      rust_name: "me_ref",
-                      r_name: "me_ref",
-                      mod_name: "me_ref",
+                      doc: "",
+                      rust_name: "leak_implicit_strings",
+                      r_name: "leak_implicit_strings",
+                      mod_name: "leak_implicit_strings",
                       args: args,
-                      return_type: "Self",
-                      func_ptr: wrap__MySubmoduleClass__me_ref as *const u8,
+                      return_type: "String",
+                      func_ptr: wrap__leak_implicit_strings as *const u8,
                       hidden: false,
                   })
           }
+          fn leak_implicit_doubles(x: Doubles) -> String {
+              x.len().to_string()
+          }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__MySubmoduleClass__me_mut(
-              _self: extendr_api::SEXP,
+          pub extern "C" fn wrap__leak_implicit_doubles(
+              x: extendr_api::SEXP,
           ) -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let mut _self_robj = extendr_api::robj::Robj::from_sexp(_self);
+                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      let _return_ref_to_self = extendr_api::unwrap_or_throw(
-                              <&mut MySubmoduleClass>::from_robj(&_self_robj),
-                          )
-                          .me_mut();
-                      Ok(_self_robj)
+                      Ok(
+                          extendr_api::Robj::from(
+                              leak_implicit_doubles(<Doubles>::from_robj(&_x_robj)?),
+                          ),
+                      )
                   })
               };
               match wrap_result_state {
@@ -608,7 +988,10 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "me_mut"),
+                              format_args!(
+                                  "user function panicked: {0}",
+                                  "leak_implicit_doubles",
+                              ),
                           );
                           res
                       };
@@ -636,46 +1019,54 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__MySubmoduleClass__me_mut(metadata: &mut Vec<extendr_api::metadata::Func>) {
+          fn meta__leak_implicit_doubles(metadata: &mut Vec<extendr_api::metadata::Func>) {
               let mut args = <[_]>::into_vec(
                   #[rustc_box]
                   ::alloc::boxed::Box::new([
                       extendr_api::metadata::Arg {
-                          name: "self",
-                          arg_type: "MySubmoduleClass",
+                          name: "x",
+                          arg_type: "Doubles",
                           default: None,
                       },
                   ]),
               );
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: " Method for getting one's (ref mut) self.",
-                      rust_name: "me_mut",
-                      r_name: "me_mut",
-                      mod_name: "me_mut",
+                      doc: "",
+                      rust_name: "leak_implicit_doubles",
+                      r_name: "leak_implicit_doubles",
+                      mod_name: "leak_implicit_doubles",
                       args: args,
-                      return_type: "Self",
-                      func_ptr: wrap__MySubmoduleClass__me_mut as *const u8,
+                      return_type: "String",
+                      func_ptr: wrap__leak_implicit_doubles as *const u8,
                       hidden: false,
                   })
           }
+          fn leak_arg2_try_implicit_strings(_y: Doubles, x: Strings) -> String {
+              x.len().to_string()
+          }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__MySubmoduleClass__me_explicit_ref(
-              _self: extendr_api::SEXP,
+          pub extern "C" fn wrap__leak_arg2_try_implicit_strings(
+              _y: extendr_api::SEXP,
+              x: extendr_api::SEXP,
           ) -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let mut _self_robj = extendr_api::robj::Robj::from_sexp(_self);
+                  let __y_robj = extendr_api::robj::Robj::from_sexp(_y);
+                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      let _return_ref_to_self = extendr_api::unwrap_or_throw(
-                              <&MySubmoduleClass>::from_robj(&_self_robj),
-                          )
-                          .me_explicit_ref();
-                      Ok(_self_robj)
+                      Ok(
+                          extendr_api::Robj::from(
+                              leak_arg2_try_implicit_strings(
+                                  __y_robj.try_into()?,
+                                  _x_robj.try_into()?,
+                              ),
+                          ),
+                      )
                   })
               };
               match wrap_result_state {
@@ -691,7 +1082,10 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "me_explicit_ref"),
+                              format_args!(
+                                  "user function panicked: {0}",
+                                  "leak_arg2_try_implicit_strings",
+                              ),
                           );
                           res
                       };
@@ -719,48 +1113,61 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__MySubmoduleClass__me_explicit_ref(
+          fn meta__leak_arg2_try_implicit_strings(
               metadata: &mut Vec<extendr_api::metadata::Func>,
           ) {
               let mut args = <[_]>::into_vec(
                   #[rustc_box]
                   ::alloc::boxed::Box::new([
                       extendr_api::metadata::Arg {
-                          name: "self",
-                          arg_type: "MySubmoduleClass",
+                          name: "_y",
+                          arg_type: "Doubles",
                           default: None,
                       },
-                  ]),
-              );
+                      extendr_api::metadata::Arg {
+                          name: "x",
+                          arg_type: "Strings",
+                          default: None,
+                      },
+                  ]),
+              );
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: " Method for getting one's ref (explicit) self.",
-                      rust_name: "me_explicit_ref",
-                      r_name: "me_explicit_ref",
-                      mod_name: "me_explicit_ref",
+                      doc: "",
+                      rust_name: "leak_arg2_try_implicit_strings",
+                      r_name: "leak_arg2_try_implicit_strings",
+                      mod_name: "leak_arg2_try_implicit_strings",
                       args: args,
-                      return_type: "MySubmoduleClass",
-                      func_ptr: wrap__MySubmoduleClass__me_explicit_ref as *const u8,
+                      return_type: "String",
+                      func_ptr: wrap__leak_arg2_try_implicit_strings as *const u8,
                       hidden: false,
                   })
           }
+          fn leak_arg2_try_implicit_doubles(_y: Doubles, x: Doubles) -> String {
+              x.len().to_string()
+          }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__MySubmoduleClass__me_explicit_mut(
-              _self: extendr_api::SEXP,
+          pub extern "C" fn wrap__leak_arg2_try_implicit_doubles(
+              _y: extendr_api::SEXP,
+              x: extendr_api::SEXP,
           ) -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let mut _self_robj = extendr_api::robj::Robj::from_sexp(_self);
+                  let __y_robj = extendr_api::robj::Robj::from_sexp(_y);
+                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      let _return_ref_to_self = extendr_api::unwrap_or_throw(
-                              <&mut MySubmoduleClass>::from_robj(&_self_robj),
-                          )
-                          .me_explicit_mut();
-                      Ok(_self_robj)
+                      Ok(
+                          extendr_api::Robj::from(
+                              leak_arg2_try_implicit_doubles(
+                                  __y_robj.try_into()?,
+                                  _x_robj.try_into()?,
+                              ),
+                          ),
+                      )
                   })
               };
               match wrap_result_state {
@@ -776,7 +1183,10 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "me_explicit_mut"),
+                              format_args!(
+                                  "user function panicked: {0}",
+                                  "leak_arg2_try_implicit_doubles",
+                              ),
                           );
                           res
                       };
@@ -804,300 +1214,324 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__MySubmoduleClass__me_explicit_mut(
+          fn meta__leak_arg2_try_implicit_doubles(
               metadata: &mut Vec<extendr_api::metadata::Func>,
           ) {
               let mut args = <[_]>::into_vec(
                   #[rustc_box]
                   ::alloc::boxed::Box::new([
                       extendr_api::metadata::Arg {
-                          name: "self",
-                          arg_type: "MySubmoduleClass",
+                          name: "_y",
+                          arg_type: "Doubles",
+                          default: None,
+                      },
+                      extendr_api::metadata::Arg {
+                          name: "x",
+                          arg_type: "Doubles",
                           default: None,
                       },
                   ]),
               );
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: " Method for getting one's ref mut (explicit) self.",
-                      rust_name: "me_explicit_mut",
-                      r_name: "me_explicit_mut",
-                      mod_name: "me_explicit_mut",
+                      doc: "",
+                      rust_name: "leak_arg2_try_implicit_doubles",
+                      r_name: "leak_arg2_try_implicit_doubles",
+                      mod_name: "leak_arg2_try_implicit_doubles",
                       args: args,
-                      return_type: "MySubmoduleClass",
-                      func_ptr: wrap__MySubmoduleClass__me_explicit_mut as *const u8,
+                      return_type: "String",
+                      func_ptr: wrap__leak_arg2_try_implicit_doubles as *const u8,
                       hidden: false,
                   })
           }
-          impl<'a> extendr_api::FromRobj<'a> for &MySubmoduleClass {
-              fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
-                  if robj.check_external_ptr_type::<MySubmoduleClass>() {
-                      #[allow(clippy::transmute_ptr_to_ref)]
-                      Ok(unsafe {
-                          std::mem::transmute(robj.external_ptr_addr::<MySubmoduleClass>())
-                      })
-                  } else {
-                      Err("expected MySubmoduleClass")
-                  }
-              }
+          fn leak_unwrap_strings(x: Robj) -> String {
+              let x = x.as_string_vector().ok_or("ERROR").unwrap();
+              x.len().to_string()
           }
-          impl<'a> extendr_api::FromRobj<'a> for &mut MySubmoduleClass {
-              fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
-                  if robj.check_external_ptr_type::<MySubmoduleClass>() {
-                      #[allow(clippy::transmute_ptr_to_ref)]
-                      Ok(unsafe {
-                          std::mem::transmute(robj.external_ptr_addr::<MySubmoduleClass>())
-                      })
-                  } else {
-                      Err("expected MySubmoduleClass")
+          #[no_mangle]
+          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
+          pub extern "C" fn wrap__leak_unwrap_strings(
+              x: extendr_api::SEXP,
+          ) -> extendr_api::SEXP {
+              use extendr_api::robj::*;
+              let wrap_result_state: std::result::Result<
+                  std::result::Result<Robj, extendr_api::Error>,
+                  Box<dyn std::any::Any + Send>,
+              > = unsafe {
+                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
+                  std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
+                      Ok(
+                          extendr_api::Robj::from(
+                              leak_unwrap_strings(<Robj>::from_robj(&_x_robj)?),
+                          ),
+                      )
+                  })
+              };
+              match wrap_result_state {
+                  Ok(Ok(zz)) => {
+                      return unsafe { zz.get() };
                   }
-              }
-          }
-          impl From<MySubmoduleClass> for Robj {
-              fn from(value: MySubmoduleClass) -> Self {
-                  unsafe {
-                      let ptr = Box::into_raw(Box::new(value));
-                      let mut res = Robj::make_external_ptr(ptr, Robj::from(()));
-                      res.set_attrib(class_symbol(), "MySubmoduleClass").unwrap();
-                      res.register_c_finalizer(Some(__finalize__MySubmoduleClass));
-                      res
+                  Ok(Err(conversion_err)) => {
+                      let err_string = conversion_err.to_string();
+                      drop(conversion_err);
+                      extendr_api::throw_r_error(&err_string);
                   }
-              }
-          }
-          impl<'a> From<&'a MySubmoduleClass> for Robj {
-              fn from(value: &'a MySubmoduleClass) -> Self {
-                  unsafe {
-                      let ptr = Box::into_raw(Box::new(value));
-                      let mut res = Robj::make_external_ptr(ptr, Robj::from(()));
-                      res.set_attrib(class_symbol(), "MySubmoduleClass").unwrap();
-                      res.register_c_finalizer(Some(__finalize__MySubmoduleClass));
-                      res
+                  Err(unwind_err) => {
+                      drop(unwind_err);
+                      let err_string = {
+                          let res = ::alloc::fmt::format(
+                              format_args!(
+                                  "user function panicked: {0}",
+                                  "leak_unwrap_strings",
+                              ),
+                          );
+                          res
+                      };
+                      extendr_api::handle_panic(
+                          err_string.as_str(),
+                          || {
+                              #[cold]
+                              #[track_caller]
+                              #[inline(never)]
+                              const fn panic_cold_explicit() -> ! {
+                                  ::core::panicking::panic_explicit()
+                              }
+                              panic_cold_explicit();
+                          },
+                      );
                   }
               }
-          }
-          extern "C" fn __finalize__MySubmoduleClass(sexp: extendr_api::SEXP) {
-              unsafe {
-                  let robj = extendr_api::robj::Robj::from_sexp(sexp);
-                  if robj.check_external_ptr_type::<MySubmoduleClass>() {
-                      let ptr = robj.external_ptr_addr::<MySubmoduleClass>();
-                      drop(Box::from_raw(ptr));
-                  }
+              {
+                  ::core::panicking::panic_fmt(
+                      format_args!(
+                          "internal error: entered unreachable code: {0}",
+                          format_args!("internal extendr error, this should never happen."),
+                      ),
+                  );
               }
           }
           #[allow(non_snake_case)]
-          fn meta__MySubmoduleClass(impls: &mut Vec<extendr_api::metadata::Impl>) {
-              let mut methods = Vec::new();
-              meta__MySubmoduleClass__new(&mut methods);
-              meta__MySubmoduleClass__set_a(&mut methods);
-              meta__MySubmoduleClass__a(&mut methods);
-              meta__MySubmoduleClass__me_owned(&mut methods);
-              meta__MySubmoduleClass__me_ref(&mut methods);
-              meta__MySubmoduleClass__me_mut(&mut methods);
-              meta__MySubmoduleClass__me_explicit_ref(&mut methods);
-              meta__MySubmoduleClass__me_explicit_mut(&mut methods);
-              impls
-                  .push(extendr_api::metadata::Impl {
-                      doc: " Class for testing (exported)\n @examples\n x <- MySubmoduleClass$new()\n x$a()\n x$set_a(10)\n x$a()\n @export",
-                      name: "MySubmoduleClass",
-                      methods,
-                  });
-          }
-          #[no_mangle]
-          #[allow(non_snake_case)]
-          pub fn get_submodule_metadata() -> extendr_api::metadata::Metadata {
-              let mut functions = Vec::new();
-              let mut impls = Vec::new();
-              meta__hello_submodule(&mut functions);
-              meta__MySubmoduleClass(&mut impls);
-              functions
-                  .push(extendr_api::metadata::Func {
-                      doc: "Metadata access function.",
-                      rust_name: "get_submodule_metadata",
-                      mod_name: "get_submodule_metadata",
-                      r_name: "get_submodule_metadata",
-                      args: Vec::new(),
-                      return_type: "Metadata",
-                      func_ptr: wrap__get_submodule_metadata as *const u8,
-                      hidden: true,
-                  });
-              functions
+          fn meta__leak_unwrap_strings(metadata: &mut Vec<extendr_api::metadata::Func>) {
+              let mut args = <[_]>::into_vec(
+                  #[rustc_box]
+                  ::alloc::boxed::Box::new([
+                      extendr_api::metadata::Arg {
+                          name: "x",
+                          arg_type: "Robj",
+                          default: None,
+                      },
+                  ]),
+              );
+              metadata
                   .push(extendr_api::metadata::Func {
-                      doc: "Wrapper generator.",
-                      rust_name: "make_submodule_wrappers",
-                      mod_name: "make_submodule_wrappers",
-                      r_name: "make_submodule_wrappers",
-                      args: <[_]>::into_vec(
-                          #[rustc_box]
-                          ::alloc::boxed::Box::new([
-                              extendr_api::metadata::Arg {
-                                  name: "use_symbols",
-                                  arg_type: "bool",
-                                  default: None,
-                              },
-                              extendr_api::metadata::Arg {
-                                  name: "package_name",
-                                  arg_type: "&str",
-                                  default: None,
-                              },
-                          ]),
-                      ),
+                      doc: "",
+                      rust_name: "leak_unwrap_strings",
+                      r_name: "leak_unwrap_strings",
+                      mod_name: "leak_unwrap_strings",
+                      args: args,
                       return_type: "String",
-                      func_ptr: wrap__make_submodule_wrappers as *const u8,
-                      hidden: true,
-                  });
-              extendr_api::metadata::Metadata {
-                  name: "submodule",
-                  functions,
-                  impls,
-              }
+                      func_ptr: wrap__leak_unwrap_strings as *const u8,
+                      hidden: false,
+                  })
           }
-          #[no_mangle]
-          #[allow(non_snake_case)]
-          pub extern "C" fn wrap__get_submodule_metadata() -> extendr_api::SEXP {
-              use extendr_api::GetSexp;
-              unsafe { extendr_api::Robj::from(get_submodule_metadata()).get() }
+          fn leak_unwrap_doubles(x: Robj) -> String {
+              x.as_real_vector().ok_or("ERROR").unwrap().len().to_string()
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__make_submodule_wrappers(
-              use_symbols_sexp: extendr_api::SEXP,
-              package_name_sexp: extendr_api::SEXP,
+          pub extern "C" fn wrap__leak_unwrap_doubles(
+              x: extendr_api::SEXP,
           ) -> extendr_api::SEXP {
-              unsafe {
-                  use extendr_api::robj::*;
-                  use extendr_api::GetSexp;
-                  let robj = Robj::from_sexp(use_symbols_sexp);
-                  let use_symbols: bool = <bool>::from_robj(&robj).unwrap();
-                  let robj = Robj::from_sexp(package_name_sexp);
-                  let package_name: &str = <&str>::from_robj(&robj).unwrap();
-                  extendr_api::Robj::from(
-                          get_submodule_metadata()
-                              .make_r_wrappers(use_symbols, package_name)
-                              .unwrap(),
+              use extendr_api::robj::*;
+              let wrap_result_state: std::result::Result<
+                  std::result::Result<Robj, extendr_api::Error>,
+                  Box<dyn std::any::Any + Send>,
+              > = unsafe {
+                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
+                  std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
+                      Ok(
+                          extendr_api::Robj::from(
+                              leak_unwrap_doubles(<Robj>::from_robj(&_x_robj)?),
+                          ),
                       )
-                      .get()
+                  })
+              };
+              match wrap_result_state {
+                  Ok(Ok(zz)) => {
+                      return unsafe { zz.get() };
+                  }
+                  Ok(Err(conversion_err)) => {
+                      let err_string = conversion_err.to_string();
+                      drop(conversion_err);
+                      extendr_api::throw_r_error(&err_string);
+                  }
+                  Err(unwind_err) => {
+                      drop(unwind_err);
+                      let err_string = {
+                          let res = ::alloc::fmt::format(
+                              format_args!(
+                                  "user function panicked: {0}",
+                                  "leak_unwrap_doubles",
+                              ),
+                          );
+                          res
+                      };
+                      extendr_api::handle_panic(
+                          err_string.as_str(),
+                          || {
+                              #[cold]
+                              #[track_caller]
+                              #[inline(never)]
+                              const fn panic_cold_explicit() -> ! {
+                                  ::core::panicking::panic_explicit()
+                              }
+                              panic_cold_explicit();
+                          },
+                      );
+                  }
+              }
+              {
+                  ::core::panicking::panic_fmt(
+                      format_args!(
+                          "internal error: entered unreachable code: {0}",
+                          format_args!("internal extendr error, this should never happen."),
+                      ),
+                  );
               }
           }
+          #[allow(non_snake_case)]
+          fn meta__leak_unwrap_doubles(metadata: &mut Vec<extendr_api::metadata::Func>) {
+              let mut args = <[_]>::into_vec(
+                  #[rustc_box]
+                  ::alloc::boxed::Box::new([
+                      extendr_api::metadata::Arg {
+                          name: "x",
+                          arg_type: "Robj",
+                          default: None,
+                      },
+                  ]),
+              );
+              metadata
+                  .push(extendr_api::metadata::Func {
+                      doc: "",
+                      rust_name: "leak_unwrap_doubles",
+                      r_name: "leak_unwrap_doubles",
+                      mod_name: "leak_unwrap_doubles",
+                      args: args,
+                      return_type: "String",
+                      func_ptr: wrap__leak_unwrap_doubles as *const u8,
+                      hidden: false,
+                  })
+          }
+          fn leak_positive_control(x: Robj) {
+              std::mem::forget(x);
+          }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn R_init_submodule_extendr(info: *mut extendr_api::DllInfo) {
-              unsafe { extendr_api::register_call_methods(info, get_submodule_metadata()) };
-          }
-      }
-      mod optional_ndarray {
-          use extendr_api::prelude::*;
-          /// Calculate Euclidean distance matrix
-          /// Test case adopted from https://github.com/mikemahoney218/examplerust/blob/23d21b1ced4e24b7a7c00dd36290114dc1bbd113/src/rust/src/lib.rs#L5
-          /// @param a : Matrix of real values or `NULL`
-          /// @export
-          fn euclidean_dist(a: Nullable<ArrayView2<Rfloat>>) -> Nullable<Doubles> {
-              if let NotNull(a) = a {
-                  let nrow = a.nrows();
-                  let result = (0..(nrow - 1))
-                      .map(|x| {
-                          ((x + 1)..nrow)
-                              .map(move |y| {
-                                  let z = &a
-                                      .slice(
-                                          match x {
-                                              r => {
-                                                  match .. {
-                                                      r => {
-                                                          let in_dim = ::ndarray::SliceNextDim::next_in_dim(
-                                                              &r,
-                                                              ::ndarray::SliceNextDim::next_in_dim(
-                                                                  &r,
-                                                                  ::core::marker::PhantomData::<::ndarray::Ix0>,
-                                                              ),
-                                                          );
-                                                          let out_dim = ::ndarray::SliceNextDim::next_out_dim(
-                                                              &r,
-                                                              ::ndarray::SliceNextDim::next_out_dim(
-                                                                  &r,
-                                                                  ::core::marker::PhantomData::<::ndarray::Ix0>,
-                                                              ),
-                                                          );
-                                                          #[allow(unsafe_code)]
-                                                          unsafe {
-                                                              ::ndarray::SliceInfo::new_unchecked(
-                                                                  [
-                                                                      <::ndarray::SliceInfoElem as ::core::convert::From<
-                                                                          _,
-                                                                      >>::from(r),
-                                                                      <::ndarray::SliceInfoElem as ::core::convert::From<
-                                                                          _,
-                                                                      >>::from(r),
-                                                                  ],
-                                                                  in_dim,
-                                                                  out_dim,
-                                                              )
-                                                          }
-                                                      }
-                                                  }
-                                              }
-                                          },
-                                      )
-                                      - &a
-                                          .slice(
-                                              match y {
-                                                  r => {
-                                                      match .. {
-                                                          r => {
-                                                              let in_dim = ::ndarray::SliceNextDim::next_in_dim(
-                                                                  &r,
-                                                                  ::ndarray::SliceNextDim::next_in_dim(
-                                                                      &r,
-                                                                      ::core::marker::PhantomData::<::ndarray::Ix0>,
-                                                                  ),
-                                                              );
-                                                              let out_dim = ::ndarray::SliceNextDim::next_out_dim(
-                                                                  &r,
-                                                                  ::ndarray::SliceNextDim::next_out_dim(
-                                                                      &r,
-                                                                      ::core::marker::PhantomData::<::ndarray::Ix0>,
-                                                                  ),
-                                                              );
-                                                              #[allow(unsafe_code)]
-                                                              unsafe {
-                                                                  ::ndarray::SliceInfo::new_unchecked(
-                                                                      [
-                                                                          <::ndarray::SliceInfoElem as ::core::convert::From<
-                                                                              _,
-                                                                          >>::from(r),
-                                                                          <::ndarray::SliceInfoElem as ::core::convert::From<
-                                                                              _,
-                                                                          >>::from(r),
-                                                                      ],
-                                                                      in_dim,
-                                                                      out_dim,
-                                                                  )
-                                                              }
-                                                          }
-                                                      }
-                                                  }
-                                              },
-                                          );
-                                  (&z * &z).iter().sum::<Rfloat>().sqrt()
-                              })
-                      })
-                      .flatten()
-                      .collect();
-                  Nullable::NotNull(result)
-              } else {
-                  Nullable::Null
+          pub extern "C" fn wrap__leak_positive_control(
+              x: extendr_api::SEXP,
+          ) -> extendr_api::SEXP {
+              use extendr_api::robj::*;
+              let wrap_result_state: std::result::Result<
+                  std::result::Result<Robj, extendr_api::Error>,
+                  Box<dyn std::any::Any + Send>,
+              > = unsafe {
+                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
+                  std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
+                      Ok(
+                          extendr_api::Robj::from(
+                              leak_positive_control(<Robj>::from_robj(&_x_robj)?),
+                          ),
+                      )
+                  })
+              };
+              match wrap_result_state {
+                  Ok(Ok(zz)) => {
+                      return unsafe { zz.get() };
+                  }
+                  Ok(Err(conversion_err)) => {
+                      let err_string = conversion_err.to_string();
+                      drop(conversion_err);
+                      extendr_api::throw_r_error(&err_string);
+                  }
+                  Err(unwind_err) => {
+                      drop(unwind_err);
+                      let err_string = {
+                          let res = ::alloc::fmt::format(
+                              format_args!(
+                                  "user function panicked: {0}",
+                                  "leak_positive_control",
+                              ),
+                          );
+                          res
+                      };
+                      extendr_api::handle_panic(
+                          err_string.as_str(),
+                          || {
+                              #[cold]
+                              #[track_caller]
+                              #[inline(never)]
+                              const fn panic_cold_explicit() -> ! {
+                                  ::core::panicking::panic_explicit()
+                              }
+                              panic_cold_explicit();
+                          },
+                      );
+                  }
               }
+              {
+                  ::core::panicking::panic_fmt(
+                      format_args!(
+                          "internal error: entered unreachable code: {0}",
+                          format_args!("internal extendr error, this should never happen."),
+                      ),
+                  );
+              }
+          }
+          #[allow(non_snake_case)]
+          fn meta__leak_positive_control(metadata: &mut Vec<extendr_api::metadata::Func>) {
+              let mut args = <[_]>::into_vec(
+                  #[rustc_box]
+                  ::alloc::boxed::Box::new([
+                      extendr_api::metadata::Arg {
+                          name: "x",
+                          arg_type: "Robj",
+                          default: None,
+                      },
+                  ]),
+              );
+              metadata
+                  .push(extendr_api::metadata::Func {
+                      doc: "",
+                      rust_name: "leak_positive_control",
+                      r_name: "leak_positive_control",
+                      mod_name: "leak_positive_control",
+                      args: args,
+                      return_type: "()",
+                      func_ptr: wrap__leak_positive_control as *const u8,
+                      hidden: false,
+                  })
+          }
+          fn leak_negative_control(x: Robj) {
+              drop(x)
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__euclidean_dist(a: extendr_api::SEXP) -> extendr_api::SEXP {
+          pub extern "C" fn wrap__leak_negative_control(
+              x: extendr_api::SEXP,
+          ) -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let _a_robj = extendr_api::robj::Robj::from_sexp(a);
+                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(extendr_api::Robj::from(euclidean_dist(_a_robj.try_into()?)))
+                      Ok(
+                          extendr_api::Robj::from(
+                              leak_negative_control(<Robj>::from_robj(&_x_robj)?),
+                          ),
+                      )
                   })
               };
               match wrap_result_state {
@@ -1113,7 +1547,10 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "euclidean_dist"),
+                              format_args!(
+                                  "user function panicked: {0}",
+                                  "leak_negative_control",
+                              ),
                           );
                           res
                       };
@@ -1141,52 +1578,59 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__euclidean_dist(metadata: &mut Vec<extendr_api::metadata::Func>) {
+          fn meta__leak_negative_control(metadata: &mut Vec<extendr_api::metadata::Func>) {
               let mut args = <[_]>::into_vec(
                   #[rustc_box]
                   ::alloc::boxed::Box::new([
                       extendr_api::metadata::Arg {
-                          name: "a",
-                          arg_type: "Nullable",
+                          name: "x",
+                          arg_type: "Robj",
                           default: None,
                       },
                   ]),
               );
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: " Calculate Euclidean distance matrix\n Test case adopted from https://github.com/mikemahoney218/examplerust/blob/23d21b1ced4e24b7a7c00dd36290114dc1bbd113/src/rust/src/lib.rs#L5\n @param a : Matrix of real values or `NULL`\n @export",
-                      rust_name: "euclidean_dist",
-                      r_name: "euclidean_dist",
-                      mod_name: "euclidean_dist",
+                      doc: "",
+                      rust_name: "leak_negative_control",
+                      r_name: "leak_negative_control",
+                      mod_name: "leak_negative_control",
                       args: args,
-                      return_type: "Nullable",
-                      func_ptr: wrap__euclidean_dist as *const u8,
+                      return_type: "()",
+                      func_ptr: wrap__leak_negative_control as *const u8,
                       hidden: false,
                   })
           }
           #[no_mangle]
           #[allow(non_snake_case)]
-          pub fn get_optional_ndarray_metadata() -> extendr_api::metadata::Metadata {
+          pub fn get_memory_leaks_metadata() -> extendr_api::metadata::Metadata {
               let mut functions = Vec::new();
               let mut impls = Vec::new();
-              meta__euclidean_dist(&mut functions);
+              meta__leak_implicit_strings(&mut functions);
+              meta__leak_implicit_doubles(&mut functions);
+              meta__leak_arg2_try_implicit_strings(&mut functions);
+              meta__leak_arg2_try_implicit_doubles(&mut functions);
+              meta__leak_unwrap_strings(&mut functions);
+              meta__leak_unwrap_doubles(&mut functions);
+              meta__leak_positive_control(&mut functions);
+              meta__leak_negative_control(&mut functions);
               functions
                   .push(extendr_api::metadata::Func {
                       doc: "Metadata access function.",
-                      rust_name: "get_optional_ndarray_metadata",
-                      mod_name: "get_optional_ndarray_metadata",
-                      r_name: "get_optional_ndarray_metadata",
+                      rust_name: "get_memory_leaks_metadata",
+                      mod_name: "get_memory_leaks_metadata",
+                      r_name: "get_memory_leaks_metadata",
                       args: Vec::new(),
                       return_type: "Metadata",
-                      func_ptr: wrap__get_optional_ndarray_metadata as *const u8,
+                      func_ptr: wrap__get_memory_leaks_metadata as *const u8,
                       hidden: true,
                   });
               functions
                   .push(extendr_api::metadata::Func {
                       doc: "Wrapper generator.",
-                      rust_name: "make_optional_ndarray_wrappers",
-                      mod_name: "make_optional_ndarray_wrappers",
-                      r_name: "make_optional_ndarray_wrappers",
+                      rust_name: "make_memory_leaks_wrappers",
+                      mod_name: "make_memory_leaks_wrappers",
+                      r_name: "make_memory_leaks_wrappers",
                       args: <[_]>::into_vec(
                           #[rustc_box]
                           ::alloc::boxed::Box::new([
@@ -1203,24 +1647,24 @@
                           ]),
                       ),
                       return_type: "String",
-                      func_ptr: wrap__make_optional_ndarray_wrappers as *const u8,
+                      func_ptr: wrap__make_memory_leaks_wrappers as *const u8,
                       hidden: true,
                   });
               extendr_api::metadata::Metadata {
-                  name: "optional_ndarray",
+                  name: "memory_leaks",
                   functions,
                   impls,
               }
           }
           #[no_mangle]
           #[allow(non_snake_case)]
-          pub extern "C" fn wrap__get_optional_ndarray_metadata() -> extendr_api::SEXP {
+          pub extern "C" fn wrap__get_memory_leaks_metadata() -> extendr_api::SEXP {
               use extendr_api::GetSexp;
-              unsafe { extendr_api::Robj::from(get_optional_ndarray_metadata()).get() }
+              unsafe { extendr_api::Robj::from(get_memory_leaks_metadata()).get() }
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__make_optional_ndarray_wrappers(
+          pub extern "C" fn wrap__make_memory_leaks_wrappers(
               use_symbols_sexp: extendr_api::SEXP,
               package_name_sexp: extendr_api::SEXP,
           ) -> extendr_api::SEXP {
@@ -1232,7 +1676,7 @@
                   let robj = Robj::from_sexp(package_name_sexp);
                   let package_name: &str = <&str>::from_robj(&robj).unwrap();
                   extendr_api::Robj::from(
-                          get_optional_ndarray_metadata()
+                          get_memory_leaks_metadata()
                               .make_r_wrappers(use_symbols, package_name)
                               .unwrap(),
                       )
@@ -1241,35 +1685,8 @@
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn R_init_optional_ndarray_extendr(info: *mut extendr_api::DllInfo) {
-              unsafe {
-                  extendr_api::register_call_methods(info, get_optional_ndarray_metadata())
-              };
-          }
-      }
-      mod graphic_device {
-          use extendr_api::{graphics::*, prelude::*};
-          pub(crate) struct MyDevice<'a> {
-              pub(crate) welcome_message: &'a str,
-          }
-          impl<'a> DeviceDriver for MyDevice<'a> {
-              fn activate(&mut self, _dd: DevDesc) {
-                  let welcome_message = self.welcome_message;
-                  print_r_output({
-                      let res = ::alloc::fmt::format(
-                          format_args!("message from device: {0}", welcome_message),
-                      );
-                      res
-                  });
-                  print_r_output("\n");
-              }
-              fn close(&mut self, _dd: DevDesc) {
-                  print_r_output({
-                      let res = ::alloc::fmt::format(format_args!("good bye..."));
-                      res
-                  });
-                  print_r_output("\n");
-              }
+          pub extern "C" fn R_init_memory_leaks_extendr(info: *mut extendr_api::DllInfo) {
+              unsafe { extendr_api::register_call_methods(info, get_memory_leaks_metadata()) };
           }
       }
       mod optional_either {
@@ -1397,237 +1814,165 @@
                               },
                           ]),
                       ),
-                      return_type: "String",
-                      func_ptr: wrap__make_optional_either_wrappers as *const u8,
-                      hidden: true,
-                  });
-              extendr_api::metadata::Metadata {
-                  name: "optional_either",
-                  functions,
-                  impls,
-              }
-          }
-          #[no_mangle]
-          #[allow(non_snake_case)]
-          pub extern "C" fn wrap__get_optional_either_metadata() -> extendr_api::SEXP {
-              use extendr_api::GetSexp;
-              unsafe { extendr_api::Robj::from(get_optional_either_metadata()).get() }
-          }
-          #[no_mangle]
-          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__make_optional_either_wrappers(
-              use_symbols_sexp: extendr_api::SEXP,
-              package_name_sexp: extendr_api::SEXP,
-          ) -> extendr_api::SEXP {
-              unsafe {
-                  use extendr_api::robj::*;
-                  use extendr_api::GetSexp;
-                  let robj = Robj::from_sexp(use_symbols_sexp);
-                  let use_symbols: bool = <bool>::from_robj(&robj).unwrap();
-                  let robj = Robj::from_sexp(package_name_sexp);
-                  let package_name: &str = <&str>::from_robj(&robj).unwrap();
-                  extendr_api::Robj::from(
-                          get_optional_either_metadata()
-                              .make_r_wrappers(use_symbols, package_name)
-                              .unwrap(),
-                      )
-                      .get()
-              }
-          }
-          #[no_mangle]
-          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn R_init_optional_either_extendr(info: *mut extendr_api::DllInfo) {
-              unsafe {
-                  extendr_api::register_call_methods(info, get_optional_either_metadata())
-              };
-          }
-      }
-      mod raw_identifiers {
-          use extendr_api::prelude::*;
-          /// Test raw identifiers (`r#`) in function arguments are parsed correctly.
-          /// See [Issue #582](https://github.com/extendr/extendr/issues/528) for details.
-          /// @param type : i32 or `NULL`
-          /// @export
-          fn raw_identifier_in_fn_args(r#type: Nullable<i32>) -> Nullable<i32> {
-              r#type
-          }
-          #[no_mangle]
-          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__raw_identifier_in_fn_args(
-              r#type: extendr_api::SEXP,
-          ) -> extendr_api::SEXP {
-              use extendr_api::robj::*;
-              let wrap_result_state: std::result::Result<
-                  std::result::Result<Robj, extendr_api::Error>,
-                  Box<dyn std::any::Any + Send>,
-              > = unsafe {
-                  let _type_robj = extendr_api::robj::Robj::from_sexp(r#type);
-                  std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(
-                          extendr_api::Robj::from(
-                              raw_identifier_in_fn_args(_type_robj.try_into()?),
-                          ),
-                      )
-                  })
-              };
-              match wrap_result_state {
-                  Ok(Ok(zz)) => {
-                      return unsafe { zz.get() };
-                  }
-                  Ok(Err(conversion_err)) => {
-                      let err_string = conversion_err.to_string();
-                      drop(conversion_err);
-                      extendr_api::throw_r_error(&err_string);
-                  }
-                  Err(unwind_err) => {
-                      drop(unwind_err);
-                      let err_string = {
-                          let res = ::alloc::fmt::format(
-                              format_args!(
-                                  "user function panicked: {0}",
-                                  "raw_identifier_in_fn_args",
-                              ),
-                          );
-                          res
-                      };
-                      extendr_api::handle_panic(
-                          err_string.as_str(),
-                          || {
-                              #[cold]
-                              #[track_caller]
-                              #[inline(never)]
-                              const fn panic_cold_explicit() -> ! {
-                                  ::core::panicking::panic_explicit()
-                              }
-                              panic_cold_explicit();
-                          },
-                      );
-                  }
-              }
-              {
-                  ::core::panicking::panic_fmt(
-                      format_args!(
-                          "internal error: entered unreachable code: {0}",
-                          format_args!("internal extendr error, this should never happen."),
-                      ),
-                  );
-              }
-          }
-          #[allow(non_snake_case)]
-          fn meta__raw_identifier_in_fn_args(metadata: &mut Vec<extendr_api::metadata::Func>) {
-              let mut args = <[_]>::into_vec(
-                  #[rustc_box]
-                  ::alloc::boxed::Box::new([
-                      extendr_api::metadata::Arg {
-                          name: "r#type",
-                          arg_type: "Nullable",
-                          default: Some("NULL"),
-                      },
-                  ]),
-              );
-              metadata
-                  .push(extendr_api::metadata::Func {
-                      doc: " Test raw identifiers (`r#`) in function arguments are parsed correctly.\n See [Issue #582](https://github.com/extendr/extendr/issues/528) for details.\n @param type : i32 or `NULL`\n @export",
-                      rust_name: "raw_identifier_in_fn_args",
-                      r_name: "raw_identifier_in_fn_args",
-                      mod_name: "raw_identifier_in_fn_args",
-                      args: args,
-                      return_type: "Nullable",
-                      func_ptr: wrap__raw_identifier_in_fn_args as *const u8,
-                      hidden: false,
-                  })
+                      return_type: "String",
+                      func_ptr: wrap__make_optional_either_wrappers as *const u8,
+                      hidden: true,
+                  });
+              extendr_api::metadata::Metadata {
+                  name: "optional_either",
+                  functions,
+                  impls,
+              }
           }
-          /// Test raw identifiers (`r#`) as function names are parsed correctly.
-          /// See [Issue #582](https://github.com/extendr/extendr/issues/528) for details.
-          /// @export
-          fn r#true() -> bool {
-              true
+          #[no_mangle]
+          #[allow(non_snake_case)]
+          pub extern "C" fn wrap__get_optional_either_metadata() -> extendr_api::SEXP {
+              use extendr_api::GetSexp;
+              unsafe { extendr_api::Robj::from(get_optional_either_metadata()).get() }
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__true() -> extendr_api::SEXP {
-              use extendr_api::robj::*;
-              let wrap_result_state: std::result::Result<
-                  std::result::Result<Robj, extendr_api::Error>,
-                  Box<dyn std::any::Any + Send>,
-              > = unsafe {
-                  std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(extendr_api::Robj::from(r#true()))
-                  })
-              };
-              match wrap_result_state {
-                  Ok(Ok(zz)) => {
-                      return unsafe { zz.get() };
-                  }
-                  Ok(Err(conversion_err)) => {
-                      let err_string = conversion_err.to_string();
-                      drop(conversion_err);
-                      extendr_api::throw_r_error(&err_string);
-                  }
-                  Err(unwind_err) => {
-                      drop(unwind_err);
-                      let err_string = {
-                          let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "r#true"),
-                          );
-                          res
-                      };
-                      extendr_api::handle_panic(
-                          err_string.as_str(),
-                          || {
-                              #[cold]
-                              #[track_caller]
-                              #[inline(never)]
-                              const fn panic_cold_explicit() -> ! {
-                                  ::core::panicking::panic_explicit()
-                              }
-                              panic_cold_explicit();
-                          },
-                      );
-                  }
-              }
-              {
-                  ::core::panicking::panic_fmt(
-                      format_args!(
-                          "internal error: entered unreachable code: {0}",
-                          format_args!("internal extendr error, this should never happen."),
-                      ),
-                  );
+          pub extern "C" fn wrap__make_optional_either_wrappers(
+              use_symbols_sexp: extendr_api::SEXP,
+              package_name_sexp: extendr_api::SEXP,
+          ) -> extendr_api::SEXP {
+              unsafe {
+                  use extendr_api::robj::*;
+                  use extendr_api::GetSexp;
+                  let robj = Robj::from_sexp(use_symbols_sexp);
+                  let use_symbols: bool = <bool>::from_robj(&robj).unwrap();
+                  let robj = Robj::from_sexp(package_name_sexp);
+                  let package_name: &str = <&str>::from_robj(&robj).unwrap();
+                  extendr_api::Robj::from(
+                          get_optional_either_metadata()
+                              .make_r_wrappers(use_symbols, package_name)
+                              .unwrap(),
+                      )
+                      .get()
               }
           }
-          #[allow(non_snake_case)]
-          fn meta__true(metadata: &mut Vec<extendr_api::metadata::Func>) {
-              let mut args = ::alloc::vec::Vec::new();
-              metadata
-                  .push(extendr_api::metadata::Func {
-                      doc: " Test raw identifiers (`r#`) as function names are parsed correctly.\n See [Issue #582](https://github.com/extendr/extendr/issues/528) for details.\n @export",
-                      rust_name: "r#true",
-                      r_name: "r#true",
-                      mod_name: "true",
-                      args: args,
-                      return_type: "bool",
-                      func_ptr: wrap__true as *const u8,
-                      hidden: false,
-                  })
+          #[no_mangle]
+          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
+          pub extern "C" fn R_init_optional_either_extendr(info: *mut extendr_api::DllInfo) {
+              unsafe {
+                  extendr_api::register_call_methods(info, get_optional_either_metadata())
+              };
           }
-          /// Combine raw identifiers (`r#`) as a function name and in arguments are parsed correctly.
-          /// See [Issue #582](https://github.com/extendr/extendr/issues/528) for details.
-          /// @param type : i32 or `NULL`
+      }
+      mod optional_ndarray {
+          use extendr_api::prelude::*;
+          /// Calculate Euclidean distance matrix
+          /// Test case adopted from https://github.com/mikemahoney218/examplerust/blob/23d21b1ced4e24b7a7c00dd36290114dc1bbd113/src/rust/src/lib.rs#L5
+          /// @param a : Matrix of real values or `NULL`
           /// @export
-          fn r#false(r#type: bool) -> bool {
-              !r#type
+          fn euclidean_dist(a: Nullable<ArrayView2<Rfloat>>) -> Nullable<Doubles> {
+              if let NotNull(a) = a {
+                  let nrow = a.nrows();
+                  let result = (0..(nrow - 1))
+                      .map(|x| {
+                          ((x + 1)..nrow)
+                              .map(move |y| {
+                                  let z = &a
+                                      .slice(
+                                          match x {
+                                              r => {
+                                                  match .. {
+                                                      r => {
+                                                          let in_dim = ::ndarray::SliceNextDim::next_in_dim(
+                                                              &r,
+                                                              ::ndarray::SliceNextDim::next_in_dim(
+                                                                  &r,
+                                                                  ::core::marker::PhantomData::<::ndarray::Ix0>,
+                                                              ),
+                                                          );
+                                                          let out_dim = ::ndarray::SliceNextDim::next_out_dim(
+                                                              &r,
+                                                              ::ndarray::SliceNextDim::next_out_dim(
+                                                                  &r,
+                                                                  ::core::marker::PhantomData::<::ndarray::Ix0>,
+                                                              ),
+                                                          );
+                                                          #[allow(unsafe_code)]
+                                                          unsafe {
+                                                              ::ndarray::SliceInfo::new_unchecked(
+                                                                  [
+                                                                      <::ndarray::SliceInfoElem as ::core::convert::From<
+                                                                          _,
+                                                                      >>::from(r),
+                                                                      <::ndarray::SliceInfoElem as ::core::convert::From<
+                                                                          _,
+                                                                      >>::from(r),
+                                                                  ],
+                                                                  in_dim,
+                                                                  out_dim,
+                                                              )
+                                                          }
+                                                      }
+                                                  }
+                                              }
+                                          },
+                                      )
+                                      - &a
+                                          .slice(
+                                              match y {
+                                                  r => {
+                                                      match .. {
+                                                          r => {
+                                                              let in_dim = ::ndarray::SliceNextDim::next_in_dim(
+                                                                  &r,
+                                                                  ::ndarray::SliceNextDim::next_in_dim(
+                                                                      &r,
+                                                                      ::core::marker::PhantomData::<::ndarray::Ix0>,
+                                                                  ),
+                                                              );
+                                                              let out_dim = ::ndarray::SliceNextDim::next_out_dim(
+                                                                  &r,
+                                                                  ::ndarray::SliceNextDim::next_out_dim(
+                                                                      &r,
+                                                                      ::core::marker::PhantomData::<::ndarray::Ix0>,
+                                                                  ),
+                                                              );
+                                                              #[allow(unsafe_code)]
+                                                              unsafe {
+                                                                  ::ndarray::SliceInfo::new_unchecked(
+                                                                      [
+                                                                          <::ndarray::SliceInfoElem as ::core::convert::From<
+                                                                              _,
+                                                                          >>::from(r),
+                                                                          <::ndarray::SliceInfoElem as ::core::convert::From<
+                                                                              _,
+                                                                          >>::from(r),
+                                                                      ],
+                                                                      in_dim,
+                                                                      out_dim,
+                                                                  )
+                                                              }
+                                                          }
+                                                      }
+                                                  }
+                                              },
+                                          );
+                                  (&z * &z).iter().sum::<Rfloat>().sqrt()
+                              })
+                      })
+                      .flatten()
+                      .collect();
+                  Nullable::NotNull(result)
+              } else {
+                  Nullable::Null
+              }
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__false(r#type: extendr_api::SEXP) -> extendr_api::SEXP {
+          pub extern "C" fn wrap__euclidean_dist(a: extendr_api::SEXP) -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let _type_robj = extendr_api::robj::Robj::from_sexp(r#type);
+                  let _a_robj = extendr_api::robj::Robj::from_sexp(a);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(extendr_api::Robj::from(r#false(_type_robj.try_into()?)))
+                      Ok(extendr_api::Robj::from(euclidean_dist(_a_robj.try_into()?)))
                   })
               };
               match wrap_result_state {
@@ -1643,7 +1988,7 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "r#false"),
+                              format_args!("user function panicked: {0}", "euclidean_dist"),
                           );
                           res
                       };
@@ -1671,54 +2016,52 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__false(metadata: &mut Vec<extendr_api::metadata::Func>) {
+          fn meta__euclidean_dist(metadata: &mut Vec<extendr_api::metadata::Func>) {
               let mut args = <[_]>::into_vec(
                   #[rustc_box]
                   ::alloc::boxed::Box::new([
                       extendr_api::metadata::Arg {
-                          name: "r#type",
-                          arg_type: "bool",
+                          name: "a",
+                          arg_type: "Nullable",
                           default: None,
                       },
                   ]),
               );
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: " Combine raw identifiers (`r#`) as a function name and in arguments are parsed correctly.\n See [Issue #582](https://github.com/extendr/extendr/issues/528) for details.\n @param type : i32 or `NULL`\n @export",
-                      rust_name: "r#false",
-                      r_name: "r#false",
-                      mod_name: "false",
+                      doc: " Calculate Euclidean distance matrix\n Test case adopted from https://github.com/mikemahoney218/examplerust/blob/23d21b1ced4e24b7a7c00dd36290114dc1bbd113/src/rust/src/lib.rs#L5\n @param a : Matrix of real values or `NULL`\n @export",
+                      rust_name: "euclidean_dist",
+                      r_name: "euclidean_dist",
+                      mod_name: "euclidean_dist",
                       args: args,
-                      return_type: "bool",
-                      func_ptr: wrap__false as *const u8,
+                      return_type: "Nullable",
+                      func_ptr: wrap__euclidean_dist as *const u8,
                       hidden: false,
                   })
           }
           #[no_mangle]
           #[allow(non_snake_case)]
-          pub fn get_raw_identifiers_metadata() -> extendr_api::metadata::Metadata {
+          pub fn get_optional_ndarray_metadata() -> extendr_api::metadata::Metadata {
               let mut functions = Vec::new();
               let mut impls = Vec::new();
-              meta__raw_identifier_in_fn_args(&mut functions);
-              meta__true(&mut functions);
-              meta__false(&mut functions);
+              meta__euclidean_dist(&mut functions);
               functions
                   .push(extendr_api::metadata::Func {
                       doc: "Metadata access function.",
-                      rust_name: "get_raw_identifiers_metadata",
-                      mod_name: "get_raw_identifiers_metadata",
-                      r_name: "get_raw_identifiers_metadata",
+                      rust_name: "get_optional_ndarray_metadata",
+                      mod_name: "get_optional_ndarray_metadata",
+                      r_name: "get_optional_ndarray_metadata",
                       args: Vec::new(),
                       return_type: "Metadata",
-                      func_ptr: wrap__get_raw_identifiers_metadata as *const u8,
+                      func_ptr: wrap__get_optional_ndarray_metadata as *const u8,
                       hidden: true,
                   });
               functions
-                  .push(extendr_api::metadata::Func {
-                      doc: "Wrapper generator.",
-                      rust_name: "make_raw_identifiers_wrappers",
-                      mod_name: "make_raw_identifiers_wrappers",
-                      r_name: "make_raw_identifiers_wrappers",
+                  .push(extendr_api::metadata::Func {
+                      doc: "Wrapper generator.",
+                      rust_name: "make_optional_ndarray_wrappers",
+                      mod_name: "make_optional_ndarray_wrappers",
+                      r_name: "make_optional_ndarray_wrappers",
                       args: <[_]>::into_vec(
                           #[rustc_box]
                           ::alloc::boxed::Box::new([
@@ -1735,24 +2078,24 @@
                           ]),
                       ),
                       return_type: "String",
-                      func_ptr: wrap__make_raw_identifiers_wrappers as *const u8,
+                      func_ptr: wrap__make_optional_ndarray_wrappers as *const u8,
                       hidden: true,
                   });
               extendr_api::metadata::Metadata {
-                  name: "raw_identifiers",
+                  name: "optional_ndarray",
                   functions,
                   impls,
               }
           }
           #[no_mangle]
           #[allow(non_snake_case)]
-          pub extern "C" fn wrap__get_raw_identifiers_metadata() -> extendr_api::SEXP {
+          pub extern "C" fn wrap__get_optional_ndarray_metadata() -> extendr_api::SEXP {
               use extendr_api::GetSexp;
-              unsafe { extendr_api::Robj::from(get_raw_identifiers_metadata()).get() }
+              unsafe { extendr_api::Robj::from(get_optional_ndarray_metadata()).get() }
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__make_raw_identifiers_wrappers(
+          pub extern "C" fn wrap__make_optional_ndarray_wrappers(
               use_symbols_sexp: extendr_api::SEXP,
               package_name_sexp: extendr_api::SEXP,
           ) -> extendr_api::SEXP {
@@ -1764,7 +2107,7 @@
                   let robj = Robj::from_sexp(package_name_sexp);
                   let package_name: &str = <&str>::from_robj(&robj).unwrap();
                   extendr_api::Robj::from(
-                          get_raw_identifiers_metadata()
+                          get_optional_ndarray_metadata()
                               .make_r_wrappers(use_symbols, package_name)
                               .unwrap(),
                       )
@@ -1773,32 +2116,36 @@
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn R_init_raw_identifiers_extendr(info: *mut extendr_api::DllInfo) {
+          pub extern "C" fn R_init_optional_ndarray_extendr(info: *mut extendr_api::DllInfo) {
               unsafe {
-                  extendr_api::register_call_methods(info, get_raw_identifiers_metadata())
+                  extendr_api::register_call_methods(info, get_optional_ndarray_metadata())
               };
           }
       }
-      mod memory_leaks {
+      mod raw_identifiers {
           use extendr_api::prelude::*;
-          fn leak_implicit_strings(x: Strings) -> String {
-              x.len().to_string()
+          /// Test raw identifiers (`r#`) in function arguments are parsed correctly.
+          /// See [Issue #582](https://github.com/extendr/extendr/issues/528) for details.
+          /// @param type : i32 or `NULL`
+          /// @export
+          fn raw_identifier_in_fn_args(r#type: Nullable<i32>) -> Nullable<i32> {
+              r#type
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__leak_implicit_strings(
-              x: extendr_api::SEXP,
+          pub extern "C" fn wrap__raw_identifier_in_fn_args(
+              r#type: extendr_api::SEXP,
           ) -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
+                  let _type_robj = extendr_api::robj::Robj::from_sexp(r#type);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
                       Ok(
                           extendr_api::Robj::from(
-                              leak_implicit_strings(<Strings>::from_robj(&_x_robj)?),
+                              raw_identifier_in_fn_args(_type_robj.try_into()?),
                           ),
                       )
                   })
@@ -1818,7 +2165,7 @@
                           let res = ::alloc::fmt::format(
                               format_args!(
                                   "user function panicked: {0}",
-                                  "leak_implicit_strings",
+                                  "raw_identifier_in_fn_args",
                               ),
                           );
                           res
@@ -1847,49 +2194,45 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__leak_implicit_strings(metadata: &mut Vec<extendr_api::metadata::Func>) {
+          fn meta__raw_identifier_in_fn_args(metadata: &mut Vec<extendr_api::metadata::Func>) {
               let mut args = <[_]>::into_vec(
                   #[rustc_box]
                   ::alloc::boxed::Box::new([
                       extendr_api::metadata::Arg {
-                          name: "x",
-                          arg_type: "Strings",
-                          default: None,
+                          name: "r#type",
+                          arg_type: "Nullable",
+                          default: Some("NULL"),
                       },
                   ]),
               );
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: "",
-                      rust_name: "leak_implicit_strings",
-                      r_name: "leak_implicit_strings",
-                      mod_name: "leak_implicit_strings",
+                      doc: " Test raw identifiers (`r#`) in function arguments are parsed correctly.\n See [Issue #582](https://github.com/extendr/extendr/issues/528) for details.\n @param type : i32 or `NULL`\n @export",
+                      rust_name: "raw_identifier_in_fn_args",
+                      r_name: "raw_identifier_in_fn_args",
+                      mod_name: "raw_identifier_in_fn_args",
                       args: args,
-                      return_type: "String",
-                      func_ptr: wrap__leak_implicit_strings as *const u8,
+                      return_type: "Nullable",
+                      func_ptr: wrap__raw_identifier_in_fn_args as *const u8,
                       hidden: false,
                   })
           }
-          fn leak_implicit_doubles(x: Doubles) -> String {
-              x.len().to_string()
+          /// Test raw identifiers (`r#`) as function names are parsed correctly.
+          /// See [Issue #582](https://github.com/extendr/extendr/issues/528) for details.
+          /// @export
+          fn r#true() -> bool {
+              true
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__leak_implicit_doubles(
-              x: extendr_api::SEXP,
-          ) -> extendr_api::SEXP {
+          pub extern "C" fn wrap__true() -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(
-                          extendr_api::Robj::from(
-                              leak_implicit_doubles(<Doubles>::from_robj(&_x_robj)?),
-                          ),
-                      )
+                      Ok(extendr_api::Robj::from(r#true()))
                   })
               };
               match wrap_result_state {
@@ -1905,10 +2248,7 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!(
-                                  "user function panicked: {0}",
-                                  "leak_implicit_doubles",
-                              ),
+                              format_args!("user function panicked: {0}", "r#true"),
                           );
                           res
                       };
@@ -1936,54 +2276,38 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__leak_implicit_doubles(metadata: &mut Vec<extendr_api::metadata::Func>) {
-              let mut args = <[_]>::into_vec(
-                  #[rustc_box]
-                  ::alloc::boxed::Box::new([
-                      extendr_api::metadata::Arg {
-                          name: "x",
-                          arg_type: "Doubles",
-                          default: None,
-                      },
-                  ]),
-              );
+          fn meta__true(metadata: &mut Vec<extendr_api::metadata::Func>) {
+              let mut args = ::alloc::vec::Vec::new();
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: "",
-                      rust_name: "leak_implicit_doubles",
-                      r_name: "leak_implicit_doubles",
-                      mod_name: "leak_implicit_doubles",
+                      doc: " Test raw identifiers (`r#`) as function names are parsed correctly.\n See [Issue #582](https://github.com/extendr/extendr/issues/528) for details.\n @export",
+                      rust_name: "r#true",
+                      r_name: "r#true",
+                      mod_name: "true",
                       args: args,
-                      return_type: "String",
-                      func_ptr: wrap__leak_implicit_doubles as *const u8,
+                      return_type: "bool",
+                      func_ptr: wrap__true as *const u8,
                       hidden: false,
                   })
           }
-          fn leak_arg2_try_implicit_strings(_y: Doubles, x: Strings) -> String {
-              x.len().to_string()
+          /// Combine raw identifiers (`r#`) as a function name and in arguments are parsed correctly.
+          /// See [Issue #582](https://github.com/extendr/extendr/issues/528) for details.
+          /// @param type : i32 or `NULL`
+          /// @export
+          fn r#false(r#type: bool) -> bool {
+              !r#type
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__leak_arg2_try_implicit_strings(
-              _y: extendr_api::SEXP,
-              x: extendr_api::SEXP,
-          ) -> extendr_api::SEXP {
+          pub extern "C" fn wrap__false(r#type: extendr_api::SEXP) -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let __y_robj = extendr_api::robj::Robj::from_sexp(_y);
-                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
+                  let _type_robj = extendr_api::robj::Robj::from_sexp(r#type);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(
-                          extendr_api::Robj::from(
-                              leak_arg2_try_implicit_strings(
-                                  __y_robj.try_into()?,
-                                  _x_robj.try_into()?,
-                              ),
-                          ),
-                      )
+                      Ok(extendr_api::Robj::from(r#false(_type_robj.try_into()?)))
                   })
               };
               match wrap_result_state {
@@ -1999,10 +2323,7 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!(
-                                  "user function panicked: {0}",
-                                  "leak_arg2_try_implicit_strings",
-                              ),
+                              format_args!("user function panicked: {0}", "r#false"),
                           );
                           res
                       };
@@ -2030,61 +2351,131 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__leak_arg2_try_implicit_strings(
-              metadata: &mut Vec<extendr_api::metadata::Func>,
-          ) {
+          fn meta__false(metadata: &mut Vec<extendr_api::metadata::Func>) {
               let mut args = <[_]>::into_vec(
                   #[rustc_box]
                   ::alloc::boxed::Box::new([
                       extendr_api::metadata::Arg {
-                          name: "_y",
-                          arg_type: "Doubles",
-                          default: None,
-                      },
-                      extendr_api::metadata::Arg {
-                          name: "x",
-                          arg_type: "Strings",
+                          name: "r#type",
+                          arg_type: "bool",
                           default: None,
                       },
                   ]),
               );
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: "",
-                      rust_name: "leak_arg2_try_implicit_strings",
-                      r_name: "leak_arg2_try_implicit_strings",
-                      mod_name: "leak_arg2_try_implicit_strings",
+                      doc: " Combine raw identifiers (`r#`) as a function name and in arguments are parsed correctly.\n See [Issue #582](https://github.com/extendr/extendr/issues/528) for details.\n @param type : i32 or `NULL`\n @export",
+                      rust_name: "r#false",
+                      r_name: "r#false",
+                      mod_name: "false",
                       args: args,
-                      return_type: "String",
-                      func_ptr: wrap__leak_arg2_try_implicit_strings as *const u8,
+                      return_type: "bool",
+                      func_ptr: wrap__false as *const u8,
                       hidden: false,
                   })
           }
-          fn leak_arg2_try_implicit_doubles(_y: Doubles, x: Doubles) -> String {
-              x.len().to_string()
+          #[no_mangle]
+          #[allow(non_snake_case)]
+          pub fn get_raw_identifiers_metadata() -> extendr_api::metadata::Metadata {
+              let mut functions = Vec::new();
+              let mut impls = Vec::new();
+              meta__raw_identifier_in_fn_args(&mut functions);
+              meta__true(&mut functions);
+              meta__false(&mut functions);
+              functions
+                  .push(extendr_api::metadata::Func {
+                      doc: "Metadata access function.",
+                      rust_name: "get_raw_identifiers_metadata",
+                      mod_name: "get_raw_identifiers_metadata",
+                      r_name: "get_raw_identifiers_metadata",
+                      args: Vec::new(),
+                      return_type: "Metadata",
+                      func_ptr: wrap__get_raw_identifiers_metadata as *const u8,
+                      hidden: true,
+                  });
+              functions
+                  .push(extendr_api::metadata::Func {
+                      doc: "Wrapper generator.",
+                      rust_name: "make_raw_identifiers_wrappers",
+                      mod_name: "make_raw_identifiers_wrappers",
+                      r_name: "make_raw_identifiers_wrappers",
+                      args: <[_]>::into_vec(
+                          #[rustc_box]
+                          ::alloc::boxed::Box::new([
+                              extendr_api::metadata::Arg {
+                                  name: "use_symbols",
+                                  arg_type: "bool",
+                                  default: None,
+                              },
+                              extendr_api::metadata::Arg {
+                                  name: "package_name",
+                                  arg_type: "&str",
+                                  default: None,
+                              },
+                          ]),
+                      ),
+                      return_type: "String",
+                      func_ptr: wrap__make_raw_identifiers_wrappers as *const u8,
+                      hidden: true,
+                  });
+              extendr_api::metadata::Metadata {
+                  name: "raw_identifiers",
+                  functions,
+                  impls,
+              }
+          }
+          #[no_mangle]
+          #[allow(non_snake_case)]
+          pub extern "C" fn wrap__get_raw_identifiers_metadata() -> extendr_api::SEXP {
+              use extendr_api::GetSexp;
+              unsafe { extendr_api::Robj::from(get_raw_identifiers_metadata()).get() }
+          }
+          #[no_mangle]
+          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
+          pub extern "C" fn wrap__make_raw_identifiers_wrappers(
+              use_symbols_sexp: extendr_api::SEXP,
+              package_name_sexp: extendr_api::SEXP,
+          ) -> extendr_api::SEXP {
+              unsafe {
+                  use extendr_api::robj::*;
+                  use extendr_api::GetSexp;
+                  let robj = Robj::from_sexp(use_symbols_sexp);
+                  let use_symbols: bool = <bool>::from_robj(&robj).unwrap();
+                  let robj = Robj::from_sexp(package_name_sexp);
+                  let package_name: &str = <&str>::from_robj(&robj).unwrap();
+                  extendr_api::Robj::from(
+                          get_raw_identifiers_metadata()
+                              .make_r_wrappers(use_symbols, package_name)
+                              .unwrap(),
+                      )
+                      .get()
+              }
+          }
+          #[no_mangle]
+          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
+          pub extern "C" fn R_init_raw_identifiers_extendr(info: *mut extendr_api::DllInfo) {
+              unsafe {
+                  extendr_api::register_call_methods(info, get_raw_identifiers_metadata())
+              };
+          }
+      }
+      mod submodule {
+          use extendr_api::prelude::*;
+          /// Return string `"Hello world!"` to R.
+          /// @export
+          fn hello_submodule() -> &'static str {
+              "Hello World!"
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__leak_arg2_try_implicit_doubles(
-              _y: extendr_api::SEXP,
-              x: extendr_api::SEXP,
-          ) -> extendr_api::SEXP {
+          pub extern "C" fn wrap__hello_submodule() -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let __y_robj = extendr_api::robj::Robj::from_sexp(_y);
-                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(
-                          extendr_api::Robj::from(
-                              leak_arg2_try_implicit_doubles(
-                                  __y_robj.try_into()?,
-                                  _x_robj.try_into()?,
-                              ),
-                          ),
-                      )
+                      Ok(extendr_api::Robj::from(hello_submodule()))
                   })
               };
               match wrap_result_state {
@@ -2100,10 +2491,7 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!(
-                                  "user function panicked: {0}",
-                                  "leak_arg2_try_implicit_doubles",
-                              ),
+                              format_args!("user function panicked: {0}", "hello_submodule"),
                           );
                           res
                       };
@@ -2131,146 +2519,106 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__leak_arg2_try_implicit_doubles(
-              metadata: &mut Vec<extendr_api::metadata::Func>,
-          ) {
-              let mut args = <[_]>::into_vec(
-                  #[rustc_box]
-                  ::alloc::boxed::Box::new([
-                      extendr_api::metadata::Arg {
-                          name: "_y",
-                          arg_type: "Doubles",
-                          default: None,
-                      },
-                      extendr_api::metadata::Arg {
-                          name: "x",
-                          arg_type: "Doubles",
-                          default: None,
-                      },
-                  ]),
-              );
+          fn meta__hello_submodule(metadata: &mut Vec<extendr_api::metadata::Func>) {
+              let mut args = ::alloc::vec::Vec::new();
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: "",
-                      rust_name: "leak_arg2_try_implicit_doubles",
-                      r_name: "leak_arg2_try_implicit_doubles",
-                      mod_name: "leak_arg2_try_implicit_doubles",
+                      doc: " Return string `\"Hello world!\"` to R.\n @export",
+                      rust_name: "hello_submodule",
+                      r_name: "hello_submodule",
+                      mod_name: "hello_submodule",
                       args: args,
-                      return_type: "String",
-                      func_ptr: wrap__leak_arg2_try_implicit_doubles as *const u8,
+                      return_type: "str",
+                      func_ptr: wrap__hello_submodule as *const u8,
                       hidden: false,
                   })
           }
-          fn leak_unwrap_strings(x: Robj) -> String {
-              let x = x.as_string_vector().ok_or("ERROR").unwrap();
-              x.len().to_string()
+          struct MySubmoduleClass {
+              a: i32,
           }
-          #[no_mangle]
-          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__leak_unwrap_strings(
-              x: extendr_api::SEXP,
-          ) -> extendr_api::SEXP {
-              use extendr_api::robj::*;
-              let wrap_result_state: std::result::Result<
-                  std::result::Result<Robj, extendr_api::Error>,
-                  Box<dyn std::any::Any + Send>,
-              > = unsafe {
-                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
-                  std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(
-                          extendr_api::Robj::from(
-                              leak_unwrap_strings(<Robj>::from_robj(&_x_robj)?),
-                          ),
-                      )
-                  })
-              };
-              match wrap_result_state {
-                  Ok(Ok(zz)) => {
-                      return unsafe { zz.get() };
-                  }
-                  Ok(Err(conversion_err)) => {
-                      let err_string = conversion_err.to_string();
-                      drop(conversion_err);
-                      extendr_api::throw_r_error(&err_string);
-                  }
-                  Err(unwind_err) => {
-                      drop(unwind_err);
-                      let err_string = {
-                          let res = ::alloc::fmt::format(
-                              format_args!(
-                                  "user function panicked: {0}",
-                                  "leak_unwrap_strings",
-                              ),
-                          );
-                          res
-                      };
-                      extendr_api::handle_panic(
-                          err_string.as_str(),
-                          || {
-                              #[cold]
-                              #[track_caller]
-                              #[inline(never)]
-                              const fn panic_cold_explicit() -> ! {
-                                  ::core::panicking::panic_explicit()
-                              }
-                              panic_cold_explicit();
-                          },
-                      );
+          #[automatically_derived]
+          impl ::core::default::Default for MySubmoduleClass {
+              #[inline]
+              fn default() -> MySubmoduleClass {
+                  MySubmoduleClass {
+                      a: ::core::default::Default::default(),
                   }
               }
-              {
-                  ::core::panicking::panic_fmt(
-                      format_args!(
-                          "internal error: entered unreachable code: {0}",
-                          format_args!("internal extendr error, this should never happen."),
-                      ),
-                  );
+          }
+          #[automatically_derived]
+          impl ::core::fmt::Debug for MySubmoduleClass {
+              #[inline]
+              fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+                  ::core::fmt::Formatter::debug_struct_field1_finish(
+                      f,
+                      "MySubmoduleClass",
+                      "a",
+                      &&self.a,
+                  )
               }
           }
-          #[allow(non_snake_case)]
-          fn meta__leak_unwrap_strings(metadata: &mut Vec<extendr_api::metadata::Func>) {
-              let mut args = <[_]>::into_vec(
-                  #[rustc_box]
-                  ::alloc::boxed::Box::new([
-                      extendr_api::metadata::Arg {
-                          name: "x",
-                          arg_type: "Robj",
-                          default: None,
-                      },
-                  ]),
-              );
-              metadata
-                  .push(extendr_api::metadata::Func {
-                      doc: "",
-                      rust_name: "leak_unwrap_strings",
-                      r_name: "leak_unwrap_strings",
-                      mod_name: "leak_unwrap_strings",
-                      args: args,
-                      return_type: "String",
-                      func_ptr: wrap__leak_unwrap_strings as *const u8,
-                      hidden: false,
-                  })
+          #[automatically_derived]
+          impl ::core::clone::Clone for MySubmoduleClass {
+              #[inline]
+              fn clone(&self) -> MySubmoduleClass {
+                  let _: ::core::clone::AssertParamIsClone<i32>;
+                  *self
+              }
           }
-          fn leak_unwrap_doubles(x: Robj) -> String {
-              x.as_real_vector().ok_or("ERROR").unwrap().len().to_string()
+          #[automatically_derived]
+          impl ::core::marker::Copy for MySubmoduleClass {}
+          /// Class for testing (exported)
+          /// @examples
+          /// x <- MySubmoduleClass$new()
+          /// x$a()
+          /// x$set_a(10)
+          /// x$a()
+          /// @export
+          impl MySubmoduleClass {
+              /// Method for making a new object.
+              fn new() -> Self {
+                  Self { a: 0 }
+              }
+              /// Method for setting stuff.
+              /// @param x a number
+              fn set_a(&mut self, x: i32) {
+                  self.a = x;
+              }
+              /// Method for getting stuff.
+              fn a(&self) -> i32 {
+                  self.a
+              }
+              /// Method for getting one's (by way of a copy) self.
+              fn me_owned(&self) -> Self {
+                  *self
+              }
+              /// Method for getting one's (ref) self.
+              fn me_ref(&self) -> &Self {
+                  self
+              }
+              /// Method for getting one's (ref mut) self.
+              fn me_mut(&mut self) -> &mut Self {
+                  self
+              }
+              /// Method for getting one's ref (explicit) self.
+              fn me_explicit_ref(&self) -> &MySubmoduleClass {
+                  self
+              }
+              /// Method for getting one's ref mut (explicit) self.
+              fn me_explicit_mut(&mut self) -> &mut MySubmoduleClass {
+                  self
+              }
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__leak_unwrap_doubles(
-              x: extendr_api::SEXP,
-          ) -> extendr_api::SEXP {
+          pub extern "C" fn wrap__MySubmoduleClass__new() -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(
-                          extendr_api::Robj::from(
-                              leak_unwrap_doubles(<Robj>::from_robj(&_x_robj)?),
-                          ),
-                      )
+                      Ok(extendr_api::Robj::from(<MySubmoduleClass>::new()))
                   })
               };
               match wrap_result_state {
@@ -2286,10 +2634,7 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!(
-                                  "user function panicked: {0}",
-                                  "leak_unwrap_doubles",
-                              ),
+                              format_args!("user function panicked: {0}", "new"),
                           );
                           res
                       };
@@ -2317,35 +2662,24 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__leak_unwrap_doubles(metadata: &mut Vec<extendr_api::metadata::Func>) {
-              let mut args = <[_]>::into_vec(
-                  #[rustc_box]
-                  ::alloc::boxed::Box::new([
-                      extendr_api::metadata::Arg {
-                          name: "x",
-                          arg_type: "Robj",
-                          default: None,
-                      },
-                  ]),
-              );
+          fn meta__MySubmoduleClass__new(metadata: &mut Vec<extendr_api::metadata::Func>) {
+              let mut args = ::alloc::vec::Vec::new();
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: "",
-                      rust_name: "leak_unwrap_doubles",
-                      r_name: "leak_unwrap_doubles",
-                      mod_name: "leak_unwrap_doubles",
+                      doc: " Method for making a new object.",
+                      rust_name: "new",
+                      r_name: "new",
+                      mod_name: "new",
                       args: args,
-                      return_type: "String",
-                      func_ptr: wrap__leak_unwrap_doubles as *const u8,
+                      return_type: "Self",
+                      func_ptr: wrap__MySubmoduleClass__new as *const u8,
                       hidden: false,
                   })
           }
-          fn leak_positive_control(x: Robj) {
-              std::mem::forget(x);
-          }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__leak_positive_control(
+          pub extern "C" fn wrap__MySubmoduleClass__set_a(
+              _self: extendr_api::SEXP,
               x: extendr_api::SEXP,
           ) -> extendr_api::SEXP {
               use extendr_api::robj::*;
@@ -2353,11 +2687,15 @@
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
+                  let mut _self_robj = extendr_api::robj::Robj::from_sexp(_self);
                   let _x_robj = extendr_api::robj::Robj::from_sexp(x);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
                       Ok(
                           extendr_api::Robj::from(
-                              leak_positive_control(<Robj>::from_robj(&_x_robj)?),
+                              extendr_api::unwrap_or_throw(
+                                      <&mut MySubmoduleClass>::from_robj(&_self_robj),
+                                  )
+                                  .set_a(<i32>::from_robj(&_x_robj)?),
                           ),
                       )
                   })
@@ -2375,10 +2713,7 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!(
-                                  "user function panicked: {0}",
-                                  "leak_positive_control",
-                              ),
+                              format_args!("user function panicked: {0}", "set_a"),
                           );
                           res
                       };
@@ -2406,47 +2741,52 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__leak_positive_control(metadata: &mut Vec<extendr_api::metadata::Func>) {
+          fn meta__MySubmoduleClass__set_a(metadata: &mut Vec<extendr_api::metadata::Func>) {
               let mut args = <[_]>::into_vec(
                   #[rustc_box]
                   ::alloc::boxed::Box::new([
+                      extendr_api::metadata::Arg {
+                          name: "self",
+                          arg_type: "MySubmoduleClass",
+                          default: None,
+                      },
                       extendr_api::metadata::Arg {
                           name: "x",
-                          arg_type: "Robj",
+                          arg_type: "i32",
                           default: None,
                       },
                   ]),
               );
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: "",
-                      rust_name: "leak_positive_control",
-                      r_name: "leak_positive_control",
-                      mod_name: "leak_positive_control",
+                      doc: " Method for setting stuff.\n @param x a number",
+                      rust_name: "set_a",
+                      r_name: "set_a",
+                      mod_name: "set_a",
                       args: args,
                       return_type: "()",
-                      func_ptr: wrap__leak_positive_control as *const u8,
+                      func_ptr: wrap__MySubmoduleClass__set_a as *const u8,
                       hidden: false,
                   })
           }
-          fn leak_negative_control(x: Robj) {
-              drop(x)
-          }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__leak_negative_control(
-              x: extendr_api::SEXP,
+          pub extern "C" fn wrap__MySubmoduleClass__a(
+              _self: extendr_api::SEXP,
           ) -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let _x_robj = extendr_api::robj::Robj::from_sexp(x);
+                  let mut _self_robj = extendr_api::robj::Robj::from_sexp(_self);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
                       Ok(
                           extendr_api::Robj::from(
-                              leak_negative_control(<Robj>::from_robj(&_x_robj)?),
+                              extendr_api::unwrap_or_throw(
+                                      <&MySubmoduleClass>::from_robj(&_self_robj),
+                                  )
+                                  .a(),
                           ),
                       )
                   })
@@ -2464,10 +2804,7 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!(
-                                  "user function panicked: {0}",
-                                  "leak_negative_control",
-                              ),
+                              format_args!("user function panicked: {0}", "a"),
                           );
                           res
                       };
@@ -2495,235 +2832,47 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__leak_negative_control(metadata: &mut Vec<extendr_api::metadata::Func>) {
+          fn meta__MySubmoduleClass__a(metadata: &mut Vec<extendr_api::metadata::Func>) {
               let mut args = <[_]>::into_vec(
                   #[rustc_box]
                   ::alloc::boxed::Box::new([
                       extendr_api::metadata::Arg {
-                          name: "x",
-                          arg_type: "Robj",
-                          default: None,
-                      },
-                  ]),
-              );
-              metadata
-                  .push(extendr_api::metadata::Func {
-                      doc: "",
-                      rust_name: "leak_negative_control",
-                      r_name: "leak_negative_control",
-                      mod_name: "leak_negative_control",
-                      args: args,
-                      return_type: "()",
-                      func_ptr: wrap__leak_negative_control as *const u8,
-                      hidden: false,
-                  })
-          }
-          #[no_mangle]
-          #[allow(non_snake_case)]
-          pub fn get_memory_leaks_metadata() -> extendr_api::metadata::Metadata {
-              let mut functions = Vec::new();
-              let mut impls = Vec::new();
-              meta__leak_implicit_strings(&mut functions);
-              meta__leak_implicit_doubles(&mut functions);
-              meta__leak_arg2_try_implicit_strings(&mut functions);
-              meta__leak_arg2_try_implicit_doubles(&mut functions);
-              meta__leak_unwrap_strings(&mut functions);
-              meta__leak_unwrap_doubles(&mut functions);
-              meta__leak_positive_control(&mut functions);
-              meta__leak_negative_control(&mut functions);
-              functions
-                  .push(extendr_api::metadata::Func {
-                      doc: "Metadata access function.",
-                      rust_name: "get_memory_leaks_metadata",
-                      mod_name: "get_memory_leaks_metadata",
-                      r_name: "get_memory_leaks_metadata",
-                      args: Vec::new(),
-                      return_type: "Metadata",
-                      func_ptr: wrap__get_memory_leaks_metadata as *const u8,
-                      hidden: true,
-                  });
-              functions
-                  .push(extendr_api::metadata::Func {
-                      doc: "Wrapper generator.",
-                      rust_name: "make_memory_leaks_wrappers",
-                      mod_name: "make_memory_leaks_wrappers",
-                      r_name: "make_memory_leaks_wrappers",
-                      args: <[_]>::into_vec(
-                          #[rustc_box]
-                          ::alloc::boxed::Box::new([
-                              extendr_api::metadata::Arg {
-                                  name: "use_symbols",
-                                  arg_type: "bool",
-                                  default: None,
-                              },
-                              extendr_api::metadata::Arg {
-                                  name: "package_name",
-                                  arg_type: "&str",
-                                  default: None,
-                              },
-                          ]),
-                      ),
-                      return_type: "String",
-                      func_ptr: wrap__make_memory_leaks_wrappers as *const u8,
-                      hidden: true,
-                  });
-              extendr_api::metadata::Metadata {
-                  name: "memory_leaks",
-                  functions,
-                  impls,
-              }
-          }
-          #[no_mangle]
-          #[allow(non_snake_case)]
-          pub extern "C" fn wrap__get_memory_leaks_metadata() -> extendr_api::SEXP {
-              use extendr_api::GetSexp;
-              unsafe { extendr_api::Robj::from(get_memory_leaks_metadata()).get() }
-          }
-          #[no_mangle]
-          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__make_memory_leaks_wrappers(
-              use_symbols_sexp: extendr_api::SEXP,
-              package_name_sexp: extendr_api::SEXP,
-          ) -> extendr_api::SEXP {
-              unsafe {
-                  use extendr_api::robj::*;
-                  use extendr_api::GetSexp;
-                  let robj = Robj::from_sexp(use_symbols_sexp);
-                  let use_symbols: bool = <bool>::from_robj(&robj).unwrap();
-                  let robj = Robj::from_sexp(package_name_sexp);
-                  let package_name: &str = <&str>::from_robj(&robj).unwrap();
-                  extendr_api::Robj::from(
-                          get_memory_leaks_metadata()
-                              .make_r_wrappers(use_symbols, package_name)
-                              .unwrap(),
-                      )
-                      .get()
-              }
-          }
-          #[no_mangle]
-          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn R_init_memory_leaks_extendr(info: *mut extendr_api::DllInfo) {
-              unsafe { extendr_api::register_call_methods(info, get_memory_leaks_metadata()) };
-          }
-      }
-      mod altrep {
-          use extendr_api::prelude::*;
-          pub struct VecUsize(pub Vec<Option<usize>>);
-          #[automatically_derived]
-          impl ::core::fmt::Debug for VecUsize {
-              #[inline]
-              fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-                  ::core::fmt::Formatter::debug_tuple_field1_finish(f, "VecUsize", &&self.0)
-              }
-          }
-          #[automatically_derived]
-          impl ::core::clone::Clone for VecUsize {
-              #[inline]
-              fn clone(&self) -> VecUsize {
-                  VecUsize(::core::clone::Clone::clone(&self.0))
-              }
-          }
-          impl AltrepImpl for VecUsize {
-              fn length(&self) -> usize {
-                  self.0.len()
-              }
-          }
-          #[cfg(use_r_altlist)]
-          impl VecUsize {}
-          impl<'a> extendr_api::FromRobj<'a> for &VecUsize {
-              fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
-                  if robj.check_external_ptr_type::<VecUsize>() {
-                      #[allow(clippy::transmute_ptr_to_ref)]
-                      Ok(unsafe { std::mem::transmute(robj.external_ptr_addr::<VecUsize>()) })
-                  } else {
-                      Err("expected VecUsize")
-                  }
-              }
-          }
-          impl<'a> extendr_api::FromRobj<'a> for &mut VecUsize {
-              fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
-                  if robj.check_external_ptr_type::<VecUsize>() {
-                      #[allow(clippy::transmute_ptr_to_ref)]
-                      Ok(unsafe { std::mem::transmute(robj.external_ptr_addr::<VecUsize>()) })
-                  } else {
-                      Err("expected VecUsize")
-                  }
-              }
-          }
-          impl From<VecUsize> for Robj {
-              fn from(value: VecUsize) -> Self {
-                  unsafe {
-                      let ptr = Box::into_raw(Box::new(value));
-                      let mut res = Robj::make_external_ptr(ptr, Robj::from(()));
-                      res.set_attrib(class_symbol(), "VecUsize").unwrap();
-                      res.register_c_finalizer(Some(__finalize__VecUsize));
-                      res
-                  }
-              }
-          }
-          impl<'a> From<&'a VecUsize> for Robj {
-              fn from(value: &'a VecUsize) -> Self {
-                  unsafe {
-                      let ptr = Box::into_raw(Box::new(value));
-                      let mut res = Robj::make_external_ptr(ptr, Robj::from(()));
-                      res.set_attrib(class_symbol(), "VecUsize").unwrap();
-                      res.register_c_finalizer(Some(__finalize__VecUsize));
-                      res
-                  }
-              }
-          }
-          extern "C" fn __finalize__VecUsize(sexp: extendr_api::SEXP) {
-              unsafe {
-                  let robj = extendr_api::robj::Robj::from_sexp(sexp);
-                  if robj.check_external_ptr_type::<VecUsize>() {
-                      let ptr = robj.external_ptr_addr::<VecUsize>();
-                      drop(Box::from_raw(ptr));
-                  }
-              }
-          }
-          #[allow(non_snake_case)]
-          fn meta__VecUsize(impls: &mut Vec<extendr_api::metadata::Impl>) {
-              let mut methods = Vec::new();
-              impls
-                  .push(extendr_api::metadata::Impl {
-                      doc: "",
-                      name: "VecUsize",
-                      methods,
-                  });
-          }
-          #[cfg(use_r_altlist)]
-          impl AltListImpl for VecUsize {
-              fn elt(&self, index: usize) -> Robj {
-                  self.into_robj()
-              }
-          }
-          #[cfg(use_r_altlist)]
-          fn new_usize(robj: Integers) -> Altrep {
-              let x = robj
-                  .iter()
-                  .map(|x| match &x {
-                      _ if x.is_na() => None,
-                      _ if x.inner() < 0 => None,
-                      _ => Some(x.inner() as usize),
+                          name: "self",
+                          arg_type: "MySubmoduleClass",
+                          default: None,
+                      },
+                  ]),
+              );
+              metadata
+                  .push(extendr_api::metadata::Func {
+                      doc: " Method for getting stuff.",
+                      rust_name: "a",
+                      r_name: "a",
+                      mod_name: "a",
+                      args: args,
+                      return_type: "i32",
+                      func_ptr: wrap__MySubmoduleClass__a as *const u8,
+                      hidden: false,
                   })
-                  .collect();
-              let obj = VecUsize(x);
-              let class = Altrep::make_altlist_class::<VecUsize>("li", "mypkg");
-              Altrep::from_state_and_class(obj, class, false)
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__new_usize(robj: extendr_api::SEXP) -> extendr_api::SEXP {
+          pub extern "C" fn wrap__MySubmoduleClass__me_owned(
+              _self: extendr_api::SEXP,
+          ) -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
-                  let _robj_robj = extendr_api::robj::Robj::from_sexp(robj);
+                  let mut _self_robj = extendr_api::robj::Robj::from_sexp(_self);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
                       Ok(
                           extendr_api::Robj::from(
-                              new_usize(<Integers>::from_robj(&_robj_robj)?),
+                              extendr_api::unwrap_or_throw(
+                                      <&MySubmoduleClass>::from_robj(&_self_robj),
+                                  )
+                                  .me_owned(),
                           ),
                       )
                   })
@@ -2741,7 +2890,7 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "new_usize"),
+                              format_args!("user function panicked: {0}", "me_owned"),
                           );
                           res
                       };
@@ -2769,82 +2918,214 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__new_usize(metadata: &mut Vec<extendr_api::metadata::Func>) {
+          fn meta__MySubmoduleClass__me_owned(
+              metadata: &mut Vec<extendr_api::metadata::Func>,
+          ) {
               let mut args = <[_]>::into_vec(
                   #[rustc_box]
                   ::alloc::boxed::Box::new([
                       extendr_api::metadata::Arg {
-                          name: "robj",
-                          arg_type: "Integers",
+                          name: "self",
+                          arg_type: "MySubmoduleClass",
                           default: None,
                       },
                   ]),
               );
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: "",
-                      rust_name: "new_usize",
-                      r_name: "new_usize",
-                      mod_name: "new_usize",
+                      doc: " Method for getting one's (by way of a copy) self.",
+                      rust_name: "me_owned",
+                      r_name: "me_owned",
+                      mod_name: "me_owned",
                       args: args,
-                      return_type: "Altrep",
-                      func_ptr: wrap__new_usize as *const u8,
+                      return_type: "Self",
+                      func_ptr: wrap__MySubmoduleClass__me_owned as *const u8,
                       hidden: false,
                   })
           }
-          struct StringInts {
-              len: usize,
-          }
-          #[automatically_derived]
-          impl ::core::fmt::Debug for StringInts {
-              #[inline]
-              fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-                  ::core::fmt::Formatter::debug_struct_field1_finish(
-                      f,
-                      "StringInts",
-                      "len",
-                      &&self.len,
-                  )
-              }
-          }
-          #[automatically_derived]
-          impl ::core::clone::Clone for StringInts {
-              #[inline]
-              fn clone(&self) -> StringInts {
-                  StringInts {
-                      len: ::core::clone::Clone::clone(&self.len),
+          #[no_mangle]
+          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
+          pub extern "C" fn wrap__MySubmoduleClass__me_ref(
+              _self: extendr_api::SEXP,
+          ) -> extendr_api::SEXP {
+              use extendr_api::robj::*;
+              let wrap_result_state: std::result::Result<
+                  std::result::Result<Robj, extendr_api::Error>,
+                  Box<dyn std::any::Any + Send>,
+              > = unsafe {
+                  let mut _self_robj = extendr_api::robj::Robj::from_sexp(_self);
+                  std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
+                      let _return_ref_to_self = extendr_api::unwrap_or_throw(
+                              <&MySubmoduleClass>::from_robj(&_self_robj),
+                          )
+                          .me_ref();
+                      Ok(_self_robj)
+                  })
+              };
+              match wrap_result_state {
+                  Ok(Ok(zz)) => {
+                      return unsafe { zz.get() };
+                  }
+                  Ok(Err(conversion_err)) => {
+                      let err_string = conversion_err.to_string();
+                      drop(conversion_err);
+                      extendr_api::throw_r_error(&err_string);
+                  }
+                  Err(unwind_err) => {
+                      drop(unwind_err);
+                      let err_string = {
+                          let res = ::alloc::fmt::format(
+                              format_args!("user function panicked: {0}", "me_ref"),
+                          );
+                          res
+                      };
+                      extendr_api::handle_panic(
+                          err_string.as_str(),
+                          || {
+                              #[cold]
+                              #[track_caller]
+                              #[inline(never)]
+                              const fn panic_cold_explicit() -> ! {
+                                  ::core::panicking::panic_explicit()
+                              }
+                              panic_cold_explicit();
+                          },
+                      );
                   }
               }
-          }
-          impl AltrepImpl for StringInts {
-              fn length(&self) -> usize {
-                  self.len as usize
+              {
+                  ::core::panicking::panic_fmt(
+                      format_args!(
+                          "internal error: entered unreachable code: {0}",
+                          format_args!("internal extendr error, this should never happen."),
+                      ),
+                  );
               }
           }
-          impl AltStringImpl for StringInts {
-              fn elt(&self, index: usize) -> Rstr {
-                  {
-                      let res = ::alloc::fmt::format(format_args!("{0}", index));
-                      res
+          #[allow(non_snake_case)]
+          fn meta__MySubmoduleClass__me_ref(metadata: &mut Vec<extendr_api::metadata::Func>) {
+              let mut args = <[_]>::into_vec(
+                  #[rustc_box]
+                  ::alloc::boxed::Box::new([
+                      extendr_api::metadata::Arg {
+                          name: "self",
+                          arg_type: "MySubmoduleClass",
+                          default: None,
+                      },
+                  ]),
+              );
+              metadata
+                  .push(extendr_api::metadata::Func {
+                      doc: " Method for getting one's (ref) self.",
+                      rust_name: "me_ref",
+                      r_name: "me_ref",
+                      mod_name: "me_ref",
+                      args: args,
+                      return_type: "Self",
+                      func_ptr: wrap__MySubmoduleClass__me_ref as *const u8,
+                      hidden: false,
+                  })
+          }
+          #[no_mangle]
+          #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
+          pub extern "C" fn wrap__MySubmoduleClass__me_mut(
+              _self: extendr_api::SEXP,
+          ) -> extendr_api::SEXP {
+              use extendr_api::robj::*;
+              let wrap_result_state: std::result::Result<
+                  std::result::Result<Robj, extendr_api::Error>,
+                  Box<dyn std::any::Any + Send>,
+              > = unsafe {
+                  let mut _self_robj = extendr_api::robj::Robj::from_sexp(_self);
+                  std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
+                      let _return_ref_to_self = extendr_api::unwrap_or_throw(
+                              <&mut MySubmoduleClass>::from_robj(&_self_robj),
+                          )
+                          .me_mut();
+                      Ok(_self_robj)
+                  })
+              };
+              match wrap_result_state {
+                  Ok(Ok(zz)) => {
+                      return unsafe { zz.get() };
                   }
-                      .into()
+                  Ok(Err(conversion_err)) => {
+                      let err_string = conversion_err.to_string();
+                      drop(conversion_err);
+                      extendr_api::throw_r_error(&err_string);
+                  }
+                  Err(unwind_err) => {
+                      drop(unwind_err);
+                      let err_string = {
+                          let res = ::alloc::fmt::format(
+                              format_args!("user function panicked: {0}", "me_mut"),
+                          );
+                          res
+                      };
+                      extendr_api::handle_panic(
+                          err_string.as_str(),
+                          || {
+                              #[cold]
+                              #[track_caller]
+                              #[inline(never)]
+                              const fn panic_cold_explicit() -> ! {
+                                  ::core::panicking::panic_explicit()
+                              }
+                              panic_cold_explicit();
+                          },
+                      );
+                  }
+              }
+              {
+                  ::core::panicking::panic_fmt(
+                      format_args!(
+                          "internal error: entered unreachable code: {0}",
+                          format_args!("internal extendr error, this should never happen."),
+                      ),
+                  );
               }
           }
-          fn tst_altstring() -> Altrep {
-              let mystate = StringInts { len: 10 };
-              let class = Altrep::make_altstring_class::<StringInts>("si", "mypkg");
-              Altrep::from_state_and_class(mystate, class, false)
+          #[allow(non_snake_case)]
+          fn meta__MySubmoduleClass__me_mut(metadata: &mut Vec<extendr_api::metadata::Func>) {
+              let mut args = <[_]>::into_vec(
+                  #[rustc_box]
+                  ::alloc::boxed::Box::new([
+                      extendr_api::metadata::Arg {
+                          name: "self",
+                          arg_type: "MySubmoduleClass",
+                          default: None,
+                      },
+                  ]),
+              );
+              metadata
+                  .push(extendr_api::metadata::Func {
+                      doc: " Method for getting one's (ref mut) self.",
+                      rust_name: "me_mut",
+                      r_name: "me_mut",
+                      mod_name: "me_mut",
+                      args: args,
+                      return_type: "Self",
+                      func_ptr: wrap__MySubmoduleClass__me_mut as *const u8,
+                      hidden: false,
+                  })
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__tst_altstring() -> extendr_api::SEXP {
+          pub extern "C" fn wrap__MySubmoduleClass__me_explicit_ref(
+              _self: extendr_api::SEXP,
+          ) -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
+                  let mut _self_robj = extendr_api::robj::Robj::from_sexp(_self);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(extendr_api::Robj::from(tst_altstring()))
+                      let _return_ref_to_self = extendr_api::unwrap_or_throw(
+                              <&MySubmoduleClass>::from_robj(&_self_robj),
+                          )
+                          .me_explicit_ref();
+                      Ok(_self_robj)
                   })
               };
               match wrap_result_state {
@@ -2860,7 +3141,7 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "tst_altstring"),
+                              format_args!("user function panicked: {0}", "me_explicit_ref"),
                           );
                           res
                       };
@@ -2888,90 +3169,48 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__tst_altstring(metadata: &mut Vec<extendr_api::metadata::Func>) {
-              let mut args = ::alloc::vec::Vec::new();
+          fn meta__MySubmoduleClass__me_explicit_ref(
+              metadata: &mut Vec<extendr_api::metadata::Func>,
+          ) {
+              let mut args = <[_]>::into_vec(
+                  #[rustc_box]
+                  ::alloc::boxed::Box::new([
+                      extendr_api::metadata::Arg {
+                          name: "self",
+                          arg_type: "MySubmoduleClass",
+                          default: None,
+                      },
+                  ]),
+              );
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: "",
-                      rust_name: "tst_altstring",
-                      r_name: "tst_altstring",
-                      mod_name: "tst_altstring",
+                      doc: " Method for getting one's ref (explicit) self.",
+                      rust_name: "me_explicit_ref",
+                      r_name: "me_explicit_ref",
+                      mod_name: "me_explicit_ref",
                       args: args,
-                      return_type: "Altrep",
-                      func_ptr: wrap__tst_altstring as *const u8,
+                      return_type: "MySubmoduleClass",
+                      func_ptr: wrap__MySubmoduleClass__me_explicit_ref as *const u8,
                       hidden: false,
                   })
           }
-          struct MyCompactIntRange {
-              start: i32,
-              len: i32,
-              step: i32,
-              missing_index: usize,
-          }
-          #[automatically_derived]
-          impl ::core::fmt::Debug for MyCompactIntRange {
-              #[inline]
-              fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-                  ::core::fmt::Formatter::debug_struct_field4_finish(
-                      f,
-                      "MyCompactIntRange",
-                      "start",
-                      &self.start,
-                      "len",
-                      &self.len,
-                      "step",
-                      &self.step,
-                      "missing_index",
-                      &&self.missing_index,
-                  )
-              }
-          }
-          #[automatically_derived]
-          impl ::core::clone::Clone for MyCompactIntRange {
-              #[inline]
-              fn clone(&self) -> MyCompactIntRange {
-                  MyCompactIntRange {
-                      start: ::core::clone::Clone::clone(&self.start),
-                      len: ::core::clone::Clone::clone(&self.len),
-                      step: ::core::clone::Clone::clone(&self.step),
-                      missing_index: ::core::clone::Clone::clone(&self.missing_index),
-                  }
-              }
-          }
-          impl AltrepImpl for MyCompactIntRange {
-              fn length(&self) -> usize {
-                  self.len as usize
-              }
-          }
-          impl AltIntegerImpl for MyCompactIntRange {
-              fn elt(&self, index: usize) -> Rint {
-                  if index == self.missing_index {
-                      Rint::na()
-                  } else {
-                      Rint::new(self.start + self.step * index as i32)
-                  }
-              }
-          }
-          fn tst_altinteger() -> Altrep {
-              let mystate = MyCompactIntRange {
-                  start: 0,
-                  len: 10,
-                  step: 1,
-                  missing_index: usize::MAX,
-              };
-              let class = Altrep::make_altinteger_class::<MyCompactIntRange>("cir", "mypkg");
-              Altrep::from_state_and_class(mystate, class.clone(), false)
-          }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__tst_altinteger() -> extendr_api::SEXP {
+          pub extern "C" fn wrap__MySubmoduleClass__me_explicit_mut(
+              _self: extendr_api::SEXP,
+          ) -> extendr_api::SEXP {
               use extendr_api::robj::*;
               let wrap_result_state: std::result::Result<
                   std::result::Result<Robj, extendr_api::Error>,
                   Box<dyn std::any::Any + Send>,
               > = unsafe {
+                  let mut _self_robj = extendr_api::robj::Robj::from_sexp(_self);
                   std::panic::catch_unwind(|| -> std::result::Result<Robj, extendr_api::Error> {
-                      Ok(extendr_api::Robj::from(tst_altinteger()))
+                      let _return_ref_to_self = extendr_api::unwrap_or_throw(
+                              <&mut MySubmoduleClass>::from_robj(&_self_robj),
+                          )
+                          .me_explicit_mut();
+                      Ok(_self_robj)
                   })
               };
               match wrap_result_state {
@@ -2987,7 +3226,7 @@
                       drop(unwind_err);
                       let err_string = {
                           let res = ::alloc::fmt::format(
-                              format_args!("user function panicked: {0}", "tst_altinteger"),
+                              format_args!("user function panicked: {0}", "me_explicit_mut"),
                           );
                           res
                       };
@@ -3015,45 +3254,128 @@
               }
           }
           #[allow(non_snake_case)]
-          fn meta__tst_altinteger(metadata: &mut Vec<extendr_api::metadata::Func>) {
-              let mut args = ::alloc::vec::Vec::new();
+          fn meta__MySubmoduleClass__me_explicit_mut(
+              metadata: &mut Vec<extendr_api::metadata::Func>,
+          ) {
+              let mut args = <[_]>::into_vec(
+                  #[rustc_box]
+                  ::alloc::boxed::Box::new([
+                      extendr_api::metadata::Arg {
+                          name: "self",
+                          arg_type: "MySubmoduleClass",
+                          default: None,
+                      },
+                  ]),
+              );
               metadata
                   .push(extendr_api::metadata::Func {
-                      doc: "",
-                      rust_name: "tst_altinteger",
-                      r_name: "tst_altinteger",
-                      mod_name: "tst_altinteger",
+                      doc: " Method for getting one's ref mut (explicit) self.",
+                      rust_name: "me_explicit_mut",
+                      r_name: "me_explicit_mut",
+                      mod_name: "me_explicit_mut",
                       args: args,
-                      return_type: "Altrep",
-                      func_ptr: wrap__tst_altinteger as *const u8,
+                      return_type: "MySubmoduleClass",
+                      func_ptr: wrap__MySubmoduleClass__me_explicit_mut as *const u8,
                       hidden: false,
                   })
           }
+          impl<'a> extendr_api::FromRobj<'a> for &MySubmoduleClass {
+              fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
+                  if robj.check_external_ptr_type::<MySubmoduleClass>() {
+                      #[allow(clippy::transmute_ptr_to_ref)]
+                      Ok(unsafe {
+                          std::mem::transmute(robj.external_ptr_addr::<MySubmoduleClass>())
+                      })
+                  } else {
+                      Err("expected MySubmoduleClass")
+                  }
+              }
+          }
+          impl<'a> extendr_api::FromRobj<'a> for &mut MySubmoduleClass {
+              fn from_robj(robj: &'a Robj) -> std::result::Result<Self, &'static str> {
+                  if robj.check_external_ptr_type::<MySubmoduleClass>() {
+                      #[allow(clippy::transmute_ptr_to_ref)]
+                      Ok(unsafe {
+                          std::mem::transmute(robj.external_ptr_addr::<MySubmoduleClass>())
+                      })
+                  } else {
+                      Err("expected MySubmoduleClass")
+                  }
+              }
+          }
+          impl From<MySubmoduleClass> for Robj {
+              fn from(value: MySubmoduleClass) -> Self {
+                  unsafe {
+                      let ptr = Box::into_raw(Box::new(value));
+                      let mut res = Robj::make_external_ptr(ptr, Robj::from(()));
+                      res.set_attrib(class_symbol(), "MySubmoduleClass").unwrap();
+                      res.register_c_finalizer(Some(__finalize__MySubmoduleClass));
+                      res
+                  }
+              }
+          }
+          impl<'a> From<&'a MySubmoduleClass> for Robj {
+              fn from(value: &'a MySubmoduleClass) -> Self {
+                  unsafe {
+                      let ptr = Box::into_raw(Box::new(value));
+                      let mut res = Robj::make_external_ptr(ptr, Robj::from(()));
+                      res.set_attrib(class_symbol(), "MySubmoduleClass").unwrap();
+                      res.register_c_finalizer(Some(__finalize__MySubmoduleClass));
+                      res
+                  }
+              }
+          }
+          extern "C" fn __finalize__MySubmoduleClass(sexp: extendr_api::SEXP) {
+              unsafe {
+                  let robj = extendr_api::robj::Robj::from_sexp(sexp);
+                  if robj.check_external_ptr_type::<MySubmoduleClass>() {
+                      let ptr = robj.external_ptr_addr::<MySubmoduleClass>();
+                      drop(Box::from_raw(ptr));
+                  }
+              }
+          }
+          #[allow(non_snake_case)]
+          fn meta__MySubmoduleClass(impls: &mut Vec<extendr_api::metadata::Impl>) {
+              let mut methods = Vec::new();
+              meta__MySubmoduleClass__new(&mut methods);
+              meta__MySubmoduleClass__set_a(&mut methods);
+              meta__MySubmoduleClass__a(&mut methods);
+              meta__MySubmoduleClass__me_owned(&mut methods);
+              meta__MySubmoduleClass__me_ref(&mut methods);
+              meta__MySubmoduleClass__me_mut(&mut methods);
+              meta__MySubmoduleClass__me_explicit_ref(&mut methods);
+              meta__MySubmoduleClass__me_explicit_mut(&mut methods);
+              impls
+                  .push(extendr_api::metadata::Impl {
+                      doc: " Class for testing (exported)\n @examples\n x <- MySubmoduleClass$new()\n x$a()\n x$set_a(10)\n x$a()\n @export",
+                      name: "MySubmoduleClass",
+                      methods,
+                  });
+          }
           #[no_mangle]
           #[allow(non_snake_case)]
-          pub fn get_altrep_metadata() -> extendr_api::metadata::Metadata {
+          pub fn get_submodule_metadata() -> extendr_api::metadata::Metadata {
               let mut functions = Vec::new();
               let mut impls = Vec::new();
-              meta__new_usize(&mut functions);
-              meta__tst_altstring(&mut functions);
-              meta__tst_altinteger(&mut functions);
+              meta__hello_submodule(&mut functions);
+              meta__MySubmoduleClass(&mut impls);
               functions
                   .push(extendr_api::metadata::Func {
                       doc: "Metadata access function.",
-                      rust_name: "get_altrep_metadata",
-                      mod_name: "get_altrep_metadata",
-                      r_name: "get_altrep_metadata",
+                      rust_name: "get_submodule_metadata",
+                      mod_name: "get_submodule_metadata",
+                      r_name: "get_submodule_metadata",
                       args: Vec::new(),
                       return_type: "Metadata",
-                      func_ptr: wrap__get_altrep_metadata as *const u8,
+                      func_ptr: wrap__get_submodule_metadata as *const u8,
                       hidden: true,
                   });
               functions
                   .push(extendr_api::metadata::Func {
                       doc: "Wrapper generator.",
-                      rust_name: "make_altrep_wrappers",
-                      mod_name: "make_altrep_wrappers",
-                      r_name: "make_altrep_wrappers",
+                      rust_name: "make_submodule_wrappers",
+                      mod_name: "make_submodule_wrappers",
+                      r_name: "make_submodule_wrappers",
                       args: <[_]>::into_vec(
                           #[rustc_box]
                           ::alloc::boxed::Box::new([
@@ -3070,24 +3392,24 @@
                           ]),
                       ),
                       return_type: "String",
-                      func_ptr: wrap__make_altrep_wrappers as *const u8,
+                      func_ptr: wrap__make_submodule_wrappers as *const u8,
                       hidden: true,
                   });
               extendr_api::metadata::Metadata {
-                  name: "altrep",
+                  name: "submodule",
                   functions,
                   impls,
               }
           }
           #[no_mangle]
           #[allow(non_snake_case)]
-          pub extern "C" fn wrap__get_altrep_metadata() -> extendr_api::SEXP {
+          pub extern "C" fn wrap__get_submodule_metadata() -> extendr_api::SEXP {
               use extendr_api::GetSexp;
-              unsafe { extendr_api::Robj::from(get_altrep_metadata()).get() }
+              unsafe { extendr_api::Robj::from(get_submodule_metadata()).get() }
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn wrap__make_altrep_wrappers(
+          pub extern "C" fn wrap__make_submodule_wrappers(
               use_symbols_sexp: extendr_api::SEXP,
               package_name_sexp: extendr_api::SEXP,
           ) -> extendr_api::SEXP {
@@ -3099,7 +3421,7 @@
                   let robj = Robj::from_sexp(package_name_sexp);
                   let package_name: &str = <&str>::from_robj(&robj).unwrap();
                   extendr_api::Robj::from(
-                          get_altrep_metadata()
+                          get_submodule_metadata()
                               .make_r_wrappers(use_symbols, package_name)
                               .unwrap(),
                       )
@@ -3108,8 +3430,8 @@
           }
           #[no_mangle]
           #[allow(non_snake_case, clippy::not_unsafe_ptr_arg_deref)]
-          pub extern "C" fn R_init_altrep_extendr(info: *mut extendr_api::DllInfo) {
-              unsafe { extendr_api::register_call_methods(info, get_altrep_metadata()) };
+          pub extern "C" fn R_init_submodule_extendr(info: *mut extendr_api::DllInfo) {
+              unsafe { extendr_api::register_call_methods(info, get_submodule_metadata()) };
           }
       }
       fn hello_world() -> &'static str {
@@ -6438,18 +6760,20 @@
           meta__MyClass(&mut impls);
           meta____MyClass(&mut impls);
           meta__MyClassUnexported(&mut impls);
-          functions.extend(submodule::get_submodule_metadata().functions);
-          functions.extend(optional_ndarray::get_optional_ndarray_metadata().functions);
+          functions.extend(altrep::get_altrep_metadata().functions);
+          functions.extend(dataframe::get_dataframe_metadata().functions);
+          functions.extend(memory_leaks::get_memory_leaks_metadata().functions);
           functions.extend(optional_either::get_optional_either_metadata().functions);
+          functions.extend(optional_ndarray::get_optional_ndarray_metadata().functions);
           functions.extend(raw_identifiers::get_raw_identifiers_metadata().functions);
-          functions.extend(memory_leaks::get_memory_leaks_metadata().functions);
-          functions.extend(altrep::get_altrep_metadata().functions);
-          impls.extend(submodule::get_submodule_metadata().impls);
-          impls.extend(optional_ndarray::get_optional_ndarray_metadata().impls);
+          functions.extend(submodule::get_submodule_metadata().functions);
+          impls.extend(altrep::get_altrep_metadata().impls);
+          impls.extend(dataframe::get_dataframe_metadata().impls);
+          impls.extend(memory_leaks::get_memory_leaks_metadata().impls);
           impls.extend(optional_either::get_optional_either_metadata().impls);
+          impls.extend(optional_ndarray::get_optional_ndarray_metadata().impls);
           impls.extend(raw_identifiers::get_raw_identifiers_metadata().impls);
-          impls.extend(memory_leaks::get_memory_leaks_metadata().impls);
-          impls.extend(altrep::get_altrep_metadata().impls);
+          impls.extend(submodule::get_submodule_metadata().impls);
           functions
               .push(extendr_api::metadata::Func {
                   doc: "Metadata access function.",
diff --git a/tests/extendrtests/tests/testthat/test-return-dataframe.R b/tests/extendrtests/tests/testthat/test-return-dataframe.R
new file mode 100644
index 000000000..9738f6c7f
--- /dev/null
+++ b/tests/extendrtests/tests/testthat/test-return-dataframe.R
@@ -0,0 +1,11 @@
+test_that("Dataframe<T> can be returned", {
+  expect_identical(
+    test_derive_into_dataframe(),
+    data.frame(x = 0:1, y = c("abc", "xyz"))
+  )
+
+  expect_identical(
+    test_into_robj_dataframe(),
+    data.frame(x = 0:1, y = c("abc", "xyz"))
+  )
+})