Skip to main content

extendr_api/
lib.rs

1//! An ergonomic, opinionated, safe and user-friendly wrapper to the R-API
2//!
3//! This library aims to provide an interface that will be familiar to
4//! first-time users of Rust or indeed any compiled language.
5//!
6//! See [`Robj`] for much of the content of this crate.
7//! [`Robj`] provides a safe wrapper for the R object type.
8//!
9//! ## Examples
10//!
11//! Use attributes and macros to export to R.
12//!
13//! ```rust,ignore
14//! use extendr_api::prelude::*;
15//! // Export a function or impl to R.
16//! #[extendr]
17//! fn fred(a: i32) -> i32 {
18//!     a + 1
19//! }
20//!
21//! // define exports using extendr_module
22//! extendr_module! {
23//!    mod mymodule;
24//!    fn fred;
25//! }
26//! ```
27//!
28//! In R:
29//!
30//! ```r
31//! result <- fred(1)
32//! ```
33//!
34//! [`Robj`] is a wrapper for R objects.
35//! The [`r!`] and `R!` macros let you build R objects
36//! using Rust and R syntax respectively.
37//! ```
38//! use extendr_api::prelude::*;
39//! test! {
40//!     // An R object with a single string "hello"
41//!     let character = r!("hello");
42//!     let character = r!(["hello", "goodbye"]);
43//!
44//!     // An R integer object with a single number 1L.
45//!     // Note that in Rust, 1 is an integer and 1.0 is a real.
46//!     let integer = r!(1);
47//!
48//!     // An R real object with a single number 1.
49//!     // Note that in R, 1 is a real and 1L is an integer.
50//!     let real = r!(1.0);
51//!
52//!     // An R real vector.
53//!     let real_vector = r!([1.0, 2.0]);
54//!     let real_vector = &[1.0, 2.0].iter().collect::<Robj>();
55//!     let real_vector = r!(vec![1.0, 2.0]);
56//!
57//!     // An R function object.
58//!     let function = R!("function(x, y) { x + y }")?;
59//!
60//!     // A named list using the list! macro.
61//!     let list = list!(a = 1, b = 2);
62//!
63//!     // An unnamed list (of R objects) using the List wrapper.
64//!     let list = r!(List::from_values(vec![1, 2, 3]));
65//!     let list = r!(List::from_values(vec!["a", "b", "c"]));
66//!     let list = r!(List::from_values(&[r!("a"), r!(1), r!(2.0)]));
67//!
68//!     // A symbol
69//!     let sym = sym!(wombat);
70//!
71//!     // A R vector using collect::<Robj>()
72//!     let vector = (0..3).map(|x| x * 10).collect::<Robj>();
73//! }
74//! ```
75//!
76//! In Rust, we prefer to use iterators rather than loops.
77//!
78//! ```
79//! use extendr_api::prelude::*;
80//! test! {
81//!     // 1 ..= 100 is the same as 1:100
82//!     let res = r!(1 ..= 100);
83//!     assert_eq!(res, R!("1:100")?);
84//!
85//!     // Rust arrays are zero-indexed so it is more common to use 0 .. 100.
86//!     let res = r!(0 .. 100);
87//!     assert_eq!(res.len(), 100);
88//!
89//!     // Using map is a super fast way to generate vectors.
90//!     let iter = (0..3).map(|i| format!("fred{}", i));
91//!     let character = iter.collect::<Robj>();
92//!     assert_eq!(character, r!(["fred0", "fred1", "fred2"]));
93//! }
94//! ```
95//!
96//! To index a vector, first convert it to a slice and then
97//! remember to use 0-based indexing. In Rust, going out of bounds
98//! will cause and error (a panic) unlike C++ which may crash.
99//! ```
100//! use extendr_api::prelude::*;
101//! test! {
102//!     let vals = r!([1.0, 2.0]);
103//!     let slice = vals.as_real_slice().ok_or("expected slice")?;
104//!     let one = slice[0];
105//!     let two = slice[1];
106//!     // let error = slice[2];
107//!     assert_eq!(one, 1.0);
108//!     assert_eq!(two, 2.0);
109//! }
110//! ```
111//!
112//! Much slower, but more general are these methods:
113//! ```
114//! use extendr_api::prelude::*;
115//! test! {
116//!     let vals = r!([1.0, 2.0, 3.0]);
117//!
118//!     // one-based indexing [[i]], returns an object.
119//!     assert_eq!(vals.index(1)?, r!(1.0));
120//!
121//!     // one-based slicing [x], returns an object.
122//!     assert_eq!(vals.slice(1..=2)?, r!([1.0, 2.0]));
123//!
124//!     // $ operator, returns an object
125//!     let list = list!(a = 1.0, b = "xyz");
126//!     assert_eq!(list.dollar("a")?, r!(1.0));
127//! }
128//! ```
129//!
130//! The [`R!`] macro lets you embed R code in Rust
131//! and takes Rust expressions in `{{ }}` pairs.
132//!
133//! The [`Rraw!`] macro will not expand the `{{ }}` pairs.
134//! ```
135//! use extendr_api::prelude::*;
136//! test! {
137//!     // The text "1 + 1" is parsed as R source code.
138//!     // The result is 1.0 + 1.0 in Rust.
139//!     assert_eq!(R!("1 + 1")?, r!(2.0));
140//!
141//!     let a = 1.0;
142//!     assert_eq!(R!("1 + {{a}}")?, r!(2.0));
143//!
144//!     assert_eq!(R!(r"
145//!         x <- {{ a }}
146//!         x + 1
147//!     ")?, r!(2.0));
148//!
149//!     assert_eq!(R!(r#"
150//!         x <- "hello"
151//!         x
152//!     "#)?, r!("hello"));
153//!
154//!     // Use the R meaning of {{ }} and do not expand.
155//!     assert_eq!(Rraw!(r"
156//!         x <- {{ 1 }}
157//!         x + 1
158//!     ")?, r!(2.0));
159//! }
160//! ```
161//!
162//! The [`r!`] macro converts a rust object to an R object
163//! and takes parameters.
164//! ```
165//! use extendr_api::prelude::*;
166//! test! {
167//!     // The text "1.0+1.0" is parsed as Rust source code.
168//!     let one = 1.0;
169//!     assert_eq!(r!(one+1.0), r!(2.0));
170//! }
171//! ```
172//!
173//! Rust has a concept of "Owned" and "Borrowed" objects.
174//!
175//! Owned objects, such as [`Vec`] and [`String`] allocate memory
176//! which is released when the object lifetime ends.
177//!
178//! Borrowed objects such as `&[i32]` and `&str` are just pointers
179//! to annother object's memory and can't live longer than the
180//! object they reference.
181//!
182//! Borrowed objects are much faster than owned objects and use less
183//! memory but are used only for temporary access.
184//!
185//! When we take a slice of an R vector, for example, we need the
186//! original R object to be alive or the data will be corrupted.
187//!
188//! ```
189//! use extendr_api::prelude::*;
190//! test! {
191//!     // robj is an "Owned" object that controls the memory allocated.
192//!     let robj = r!([1, 2, 3]);
193//!
194//!     // Here slice is a "borrowed" reference to the bytes in robj.
195//!     // and cannot live longer than robj.
196//!     let slice = robj.as_integer_slice().ok_or("expected slice")?;
197//!     assert_eq!(slice.len(), 3);
198//! }
199//! ```
200//!
201//! ## Writing tests
202//!
203//! To test the functions exposed to R, wrap your code in the [`test!`] macro.
204//! This macro starts up the necessary R machinery for tests to work.
205//!
206//! ```rust,no_run
207//! use extendr_api::prelude::*;
208//!
209//! #[extendr]
210//! fn things() ->  Strings {
211//!     Strings::from_values(vec!["Test", "this"])
212//! }
213//!
214//! // define exports using extendr_module
215//! extendr_module! {
216//!    mod mymodule;
217//!    fn things;
218//! }
219//!
220//!
221//! #[cfg(test)]
222//! mod test {
223//!     use super::*;
224//!     use extendr_api::prelude::*;
225//!
226//!     #[test]
227//!     fn test_simple_function() {
228//!         assert_eq!(things().elt(0), "Test")
229//!     }
230//! }
231//! ```
232//!
233//! ## Returning `Result<T, E>` to R
234//!
235//! Two experimental features for returning error-aware R `list`s, `result_list` and `result_condition`,
236//! can be toggled to avoid panics on `Err`. Instead, an `Err` `x` is returned as either
237//!  - list: `list(ok=NULL, err=x)` when `result_list` is enabled,
238//!  - error condition: `<error: extendr_error>`, with `x` placed in `condition$value`, when `resultd_condition` is enabled.
239//!
240//! It is currently solely up to the user to handle any result on R side.
241//!
242//! There is an added overhead of wrapping Rust results in an R `list` object.
243//!
244//! ```rust,ignore
245//! use extendr_api::prelude::*;
246//! // simple function always returning an Err string
247//! #[extendr]
248//! fn oups(a: i32) -> std::result::Result<i32, String> {
249//!     Err("I did it again".to_string())
250//! }
251//!
252//! // define exports using extendr_module
253//! extendr_module! {
254//!    mod mymodule;
255//!    fn oups;
256//! }
257//!
258//! ```
259//!
260//! In R:
261//!
262//! ```rust,ignore
263//! # default result_panic feature
264//! oups(1)
265//! > ... long panic traceback from rust printed to stderr
266//!
267//! # result_list feature
268//! lst <- oups(1)
269//! print(lst)
270//! > list(ok = NULL, err = "I did it again")
271//!
272//! # result_condition feature
273//! cnd <- oups(1)
274//! print(cnd)
275//! > <error: extendr_error>
276//! print(cnd$value)
277//! > "I did it again"
278//!
279//! # handling example for result_condition
280//! oups_handled <- function(a) {
281//!   val_or_err <- oups(1)
282//!   if (inherits(val_or_err, "extendr_error")) stop(val_or_err)
283//!   val_or_err
284//! }
285//! ```
286//!
287//! ## Feature gates
288//!
289//! extendr-api has some optional features behind these feature gates:
290//!
291//! - `ndarray`: provides the conversion between R's matrices and [`ndarray`](https://docs.rs/ndarray/latest/ndarray/).
292//! - `num-complex`: provides the conversion between R's complex numbers and [`num-complex`](https://docs.rs/num-complex/latest/num_complex/).
293//! - `serde`: provides the [`serde`](https://serde.rs/) support.
294//! - `either`: provides implementation of type conversion traits for `Either<L, R>` from [`either`](https://docs.rs/either/latest/either/) if `L` and `R` both implement those traits.
295//! - `faer`: provides conversion between R's matrices and [`faer`](https://docs.rs/faer/latest/faer/).
296//!
297//! extendr-api supports three ways of returning a Result<T,E> to R.
298//! Only one behavior feature can be enabled at a time.
299//! - `result_panic`: Default behavior, return `Ok` as is, panic! on any `Err`
300//!
301//! Default behavior can be overridden by specifying `extend_api` features, i.e. `extendr-api = {..., default-features = false, features= ["result_condition"]}`
302//! These features are experimental and are subject to change.
303//! - `result_list`: return `Ok` as `list(ok=?, err=NULL)` or `Err` `list(ok=NULL, err=?)`
304//! - `result_condition`: return `Ok` as is or `Err` as $value in an R error condition.
305#![doc(
306    html_logo_url = "https://raw.githubusercontent.com/extendr/extendr/main/extendr-logo-256.png"
307)]
308
309pub mod conditions;
310pub mod error;
311pub mod functions;
312pub mod io;
313pub mod iter;
314pub mod lang_macros;
315pub mod metadata;
316pub mod na;
317pub mod optional;
318pub mod ownership;
319pub mod prelude;
320pub mod rmacros;
321pub mod robj;
322pub mod scalar;
323pub mod thread_safety;
324pub mod wrapper;
325
326pub use robj::Robj;
327pub use std::convert::{TryFrom, TryInto};
328pub use std::ops::Deref;
329pub use std::ops::DerefMut;
330pub use std::str::FromStr;
331
332#[cfg(feature = "serde")]
333pub mod serializer;
334
335#[cfg(feature = "serde")]
336pub mod deserializer;
337
338pub(crate) mod conversions;
339
340//////////////////////////////////////////////////
341// Note these pub use statements are deprecated
342//
343// `use extendr_api::prelude::*;`
344//
345// instead.
346
347pub use error::*;
348pub use functions::*;
349pub use lang_macros::*;
350pub use na::*;
351pub use robj::*;
352pub use thread_safety::{catch_r_error, single_threaded, throw_r_error};
353pub use wrapper::*;
354
355pub use extendr_macros::*;
356
357use extendr_ffi::SEXPTYPE;
358use scalar::Rbool;
359
360//////////////////////////////////////////////////
361
362/// TRUE value eg. `r!(TRUE)`
363pub const TRUE: Rbool = Rbool::true_value();
364
365/// FALSE value eg. `r!(FALSE)`
366pub const FALSE: Rbool = Rbool::false_value();
367
368/// NULL value eg. `Robj::null()`
369pub const NULL: () = ();
370
371/// NA value for integers eg. `r!(NA_INTEGER)`
372pub const NA_INTEGER: Option<i32> = None;
373
374/// NA value for real values eg. `r!(NA_REAL)`
375pub const NA_REAL: Option<f64> = None;
376
377/// NA value for strings. `r!(NA_STRING)`
378pub const NA_STRING: Option<&str> = None;
379
380/// NA value for logical. `r!(NA_LOGICAL)`
381pub const NA_LOGICAL: Rbool = Rbool::na_value();
382
383/// This is needed for the generation of wrappers.
384#[doc(hidden)]
385pub use extendr_ffi::DllInfo;
386
387/// This is necessary for `#[extendr]`-impl
388#[doc(hidden)]
389pub use extendr_ffi::R_ExternalPtrAddr;
390
391/// This is used in `#[extendr(use_rng = true)]` on `fn`-items.
392#[doc(hidden)]
393pub use extendr_ffi::GetRNGstate;
394
395/// This is used in `#[extendr(use_rng = true)]` on `fn`-items.
396#[doc(hidden)]
397pub use extendr_ffi::PutRNGstate;
398
399#[doc(hidden)]
400pub use extendr_ffi::SEXP;
401
402#[doc(hidden)]
403pub use extendr_ffi::{R_NilValue, Rf_errorcall, Rf_warningcall};
404
405pub use metadata::Metadata;
406
407#[doc(hidden)]
408pub struct CallMethod {
409    pub call_symbol: std::ffi::CString,
410    pub func_ptr: *const u8,
411    pub num_args: i32,
412}
413
414unsafe fn make_method_def(
415    cstrings: &mut Vec<std::ffi::CString>,
416    rmethods: &mut Vec<extendr_ffi::R_CallMethodDef>,
417    func: &metadata::Func,
418    wrapped_name: &str,
419) {
420    cstrings.push(std::ffi::CString::new(wrapped_name).unwrap());
421    rmethods.push(extendr_ffi::R_CallMethodDef {
422        name: cstrings.last().unwrap().as_ptr(),
423        fun: Some(std::mem::transmute::<
424            *const u8,
425            unsafe extern "C" fn() -> *mut std::ffi::c_void,
426        >(func.func_ptr)),
427        numArgs: func.args.len() as i32,
428    });
429}
430
431// Internal function used to implement the .Call interface.
432// This is called from the code generated by the #[extendr] attribute.
433#[doc(hidden)]
434pub unsafe fn register_call_methods(info: *mut extendr_ffi::DllInfo, metadata: Metadata) {
435    let mut rmethods = Vec::new();
436    let mut cstrings = Vec::new();
437    for func in metadata.functions {
438        make_method_def(&mut cstrings, &mut rmethods, &func, func.c_name);
439    }
440
441    for imp in metadata.impls {
442        for func in imp.methods {
443            make_method_def(&mut cstrings, &mut rmethods, &func, func.c_name);
444        }
445    }
446
447    rmethods.push(extendr_ffi::R_CallMethodDef {
448        name: std::ptr::null(),
449        fun: None,
450        numArgs: 0,
451    });
452
453    extendr_ffi::R_registerRoutines(
454        info,
455        std::ptr::null(),
456        rmethods.as_ptr(),
457        std::ptr::null(),
458        std::ptr::null(),
459    );
460
461    // This seems to allow both symbols and strings,
462    extendr_ffi::R_useDynamicSymbols(info, extendr_ffi::Rboolean::FALSE);
463    extendr_ffi::R_forceSymbols(info, extendr_ffi::Rboolean::FALSE);
464}
465
466/// Type of R objects used by [Robj::rtype].
467#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
468#[non_exhaustive]
469pub enum Rtype {
470    Null,        // NILSXP
471    Symbol,      // SYMSXP
472    Pairlist,    // LISTSXP
473    Function,    // CLOSXP
474    Environment, // ENVSXP
475    Promise,     // PROMSXP
476    Language,    // LANGSXP
477    Special,     // SPECIALSXP
478    Builtin,     // BUILTINSXP
479    Rstr,        // CHARSXP
480    Logicals,    // LGLSXP
481    Integers,    // INTSXP
482    Doubles,     // REALSXP
483    Complexes,   // CPLXSXP
484    Strings,     // STRSXP
485    Dot,         // DOTSXP
486    Any,         // ANYSXP
487    List,        // VECSXP
488    Expressions, // EXPRSXP
489    Bytecode,    // BCODESXP
490    ExternalPtr, // EXTPTRSXP
491    WeakRef,     // WEAKREFSXP
492    Raw,         // RAWSXP
493    S4,          // S4SXP
494    Unknown,
495}
496
497/// Enum use to unpack R objects into their specialist wrappers.
498// Todo: convert all Robj types to wrappers.
499// Note: this only works if the wrappers are all just SEXPs.
500#[derive(Debug, PartialEq)]
501#[non_exhaustive]
502pub enum Rany<'a> {
503    Null(&'a Robj),               // NILSXP
504    Symbol(&'a Symbol),           // SYMSXP
505    Pairlist(&'a Pairlist),       // LISTSXP
506    Function(&'a Function),       // CLOSXP
507    Environment(&'a Environment), // ENVSXP
508    Promise(&'a Promise),         // PROMSXP
509    Language(&'a Language),       // LANGSXP
510    Special(&'a Primitive),       // SPECIALSXP
511    Builtin(&'a Primitive),       // BUILTINSXP
512    Rstr(&'a Rstr),               // CHARSXP
513    Logicals(&'a Logicals),       // LGLSXP
514    Integers(&'a Integers),       // INTSXP
515    Doubles(&'a Doubles),         // REALSXP
516    Complexes(&'a Complexes),     // CPLXSXP
517    Strings(&'a Strings),         // STRSXP
518    Dot(&'a Robj),                // DOTSXP
519    Any(&'a Robj),                // ANYSXP
520    List(&'a List),               // VECSXP
521    Expressions(&'a Expressions), // EXPRSXP
522    Bytecode(&'a Robj),           // BCODESXP
523    ExternalPtr(&'a Robj),        // EXTPTRSXP
524    WeakRef(&'a Robj),            // WEAKREFSXP
525    Raw(&'a Raw),                 // RAWSXP
526    S4(&'a S4),                   // S4SXP
527    Unknown(&'a Robj),
528}
529
530/// Convert extendr's Rtype to R's SEXPTYPE.
531/// Panics if the type is Unknown.
532pub fn rtype_to_sxp(rtype: Rtype) -> SEXPTYPE {
533    use extendr_ffi::SEXPTYPE;
534    match rtype {
535        Rtype::Null => SEXPTYPE::NILSXP,
536        Rtype::Symbol => SEXPTYPE::SYMSXP,
537        Rtype::Pairlist => SEXPTYPE::LISTSXP,
538        Rtype::Function => SEXPTYPE::CLOSXP,
539        Rtype::Environment => SEXPTYPE::ENVSXP,
540        Rtype::Promise => SEXPTYPE::PROMSXP,
541        Rtype::Language => SEXPTYPE::LANGSXP,
542        Rtype::Special => SEXPTYPE::SPECIALSXP,
543        Rtype::Builtin => SEXPTYPE::BUILTINSXP,
544        Rtype::Rstr => SEXPTYPE::CHARSXP,
545        Rtype::Logicals => SEXPTYPE::LGLSXP,
546        Rtype::Integers => SEXPTYPE::INTSXP,
547        Rtype::Doubles => SEXPTYPE::REALSXP,
548        Rtype::Complexes => SEXPTYPE::CPLXSXP,
549        Rtype::Strings => SEXPTYPE::STRSXP,
550        Rtype::Dot => SEXPTYPE::DOTSXP,
551        Rtype::Any => SEXPTYPE::ANYSXP,
552        Rtype::List => SEXPTYPE::VECSXP,
553        Rtype::Expressions => SEXPTYPE::EXPRSXP,
554        Rtype::Bytecode => SEXPTYPE::BCODESXP,
555        Rtype::ExternalPtr => SEXPTYPE::EXTPTRSXP,
556        Rtype::WeakRef => SEXPTYPE::WEAKREFSXP,
557        Rtype::Raw => SEXPTYPE::RAWSXP,
558        #[cfg(not(use_objsxp))]
559        Rtype::S4 => SEXPTYPE::S4SXP,
560        #[cfg(use_objsxp)]
561        Rtype::S4 => SEXPTYPE::OBJSXP,
562        Rtype::Unknown => panic!("attempt to use Unknown Rtype"),
563    }
564}
565
566/// Convert R's SEXPTYPE to extendr's Rtype.
567pub fn sxp_to_rtype(sxptype: SEXPTYPE) -> Rtype {
568    match sxptype {
569        SEXPTYPE::NILSXP => Rtype::Null,
570        SEXPTYPE::SYMSXP => Rtype::Symbol,
571        SEXPTYPE::LISTSXP => Rtype::Pairlist,
572        SEXPTYPE::CLOSXP => Rtype::Function,
573        SEXPTYPE::ENVSXP => Rtype::Environment,
574        SEXPTYPE::PROMSXP => Rtype::Promise,
575        SEXPTYPE::LANGSXP => Rtype::Language,
576        SEXPTYPE::SPECIALSXP => Rtype::Special,
577        SEXPTYPE::BUILTINSXP => Rtype::Builtin,
578        SEXPTYPE::CHARSXP => Rtype::Rstr,
579        SEXPTYPE::LGLSXP => Rtype::Logicals,
580        SEXPTYPE::INTSXP => Rtype::Integers,
581        SEXPTYPE::REALSXP => Rtype::Doubles,
582        SEXPTYPE::CPLXSXP => Rtype::Complexes,
583        SEXPTYPE::STRSXP => Rtype::Strings,
584        SEXPTYPE::DOTSXP => Rtype::Dot,
585        SEXPTYPE::ANYSXP => Rtype::Any,
586        SEXPTYPE::VECSXP => Rtype::List,
587        SEXPTYPE::EXPRSXP => Rtype::Expressions,
588        SEXPTYPE::BCODESXP => Rtype::Bytecode,
589        SEXPTYPE::EXTPTRSXP => Rtype::ExternalPtr,
590        SEXPTYPE::WEAKREFSXP => Rtype::WeakRef,
591        SEXPTYPE::RAWSXP => Rtype::Raw,
592        #[cfg(not(use_objsxp))]
593        SEXPTYPE::S4SXP => Rtype::S4,
594        #[cfg(use_objsxp)]
595        SEXPTYPE::OBJSXP => Rtype::S4,
596        _ => Rtype::Unknown,
597    }
598}
599
600const PRINTF_NO_FMT_CSTRING: &[std::os::raw::c_char] = &[37, 115, 0]; // same as "%s\0"
601#[doc(hidden)]
602pub fn print_r_output<T: Into<Vec<u8>>>(s: T) {
603    let cs = std::ffi::CString::new(s).expect("NulError");
604    unsafe {
605        extendr_ffi::Rprintf(PRINTF_NO_FMT_CSTRING.as_ptr(), cs.as_ptr());
606    }
607}
608
609#[doc(hidden)]
610pub fn print_r_error<T: Into<Vec<u8>>>(s: T) {
611    let cs = std::ffi::CString::new(s).expect("NulError");
612    unsafe {
613        extendr_ffi::REprintf(PRINTF_NO_FMT_CSTRING.as_ptr(), cs.as_ptr());
614    }
615}
616
617#[cfg(test)]
618mod tests {
619    use super::prelude::*;
620    use crate as extendr_api;
621
622    use extendr_macros::extendr;
623    use extendr_macros::extendr_module;
624    use extendr_macros::pairlist;
625
626    #[allow(clippy::too_many_arguments)]
627    #[extendr]
628    pub fn inttypes(a: i8, b: u8, c: i16, d: u16, e: i32, f: u32, g: i64, h: u64) {
629        assert_eq!(a, 1);
630        assert_eq!(b, 2);
631        assert_eq!(c, 3);
632        assert_eq!(d, 4);
633        assert_eq!(e, 5);
634        assert_eq!(f, 6);
635        assert_eq!(g, 7);
636        assert_eq!(h, 8);
637    }
638
639    #[extendr]
640    pub fn floattypes(a: f32, b: f64) {
641        assert_eq!(a, 1.);
642        assert_eq!(b, 2.);
643    }
644
645    #[extendr]
646    pub fn strtypes(a: &str, b: String) {
647        assert_eq!(a, "abc");
648        assert_eq!(b, "def");
649    }
650
651    #[extendr]
652    pub fn vectortypes(a: Vec<i32>, b: Vec<f64>) {
653        assert_eq!(a, [1, 2, 3]);
654        assert_eq!(b, [4., 5., 6.]);
655    }
656
657    #[extendr]
658    pub fn robjtype(a: Robj) {
659        assert_eq!(a, Robj::from(1))
660    }
661
662    #[extendr]
663    pub fn return_u8() -> u8 {
664        123
665    }
666
667    #[extendr]
668    pub fn return_u16() -> u16 {
669        123
670    }
671
672    #[extendr]
673    pub fn return_u32() -> u32 {
674        123
675    }
676
677    #[extendr]
678    pub fn return_u64() -> u64 {
679        123
680    }
681
682    #[extendr]
683    pub fn return_i8() -> i8 {
684        123
685    }
686
687    #[extendr]
688    pub fn return_i16() -> i16 {
689        123
690    }
691
692    #[extendr]
693    pub fn return_i32() -> i32 {
694        123
695    }
696
697    #[extendr]
698    pub fn return_i64() -> i64 {
699        123
700    }
701
702    #[extendr]
703    pub fn return_f32() -> f32 {
704        123.
705    }
706
707    #[extendr]
708    pub fn return_f64() -> f64 {
709        123.
710    }
711
712    #[extendr]
713    pub fn f64_slice(x: &[f64]) -> &[f64] {
714        x
715    }
716
717    #[extendr]
718    pub fn i32_slice(x: &[i32]) -> &[i32] {
719        x
720    }
721
722    #[extendr]
723    pub fn bool_slice(x: &[Rbool]) -> &[Rbool] {
724        x
725    }
726
727    #[extendr]
728    pub fn f64_iter(x: Doubles) -> Doubles {
729        x
730    }
731
732    #[extendr]
733    pub fn i32_iter(x: Integers) -> Integers {
734        x
735    }
736
737    // #[extendr]
738    // pub fn bool_iter(x: Logicals) -> Logicals {
739    //     x
740    // }
741
742    #[extendr]
743    pub fn symbol(x: Symbol) -> Symbol {
744        x
745    }
746
747    #[extendr]
748    pub fn matrix(x: RMatrix<f64>) -> RMatrix<f64> {
749        x
750    }
751
752    #[extendr]
753    struct Person {
754        pub name: String,
755    }
756
757    #[extendr]
758    /// impl comment.
759    impl Person {
760        fn new() -> Self {
761            Self {
762                name: "".to_string(),
763            }
764        }
765
766        fn set_name(&mut self, name: &str) {
767            self.name = name.to_string();
768        }
769
770        fn name(&self) -> &str {
771            self.name.as_str()
772        }
773    }
774
775    // see metadata_test for the following comments.
776
777    /// comment #1
778    /// comment #2
779    /**
780        comment #3
781        comment #4
782    **/
783    #[extendr]
784    /// aux_func doc comment.
785    fn aux_func(_person: &Person) {}
786
787    // Macro to generate exports
788    extendr_module! {
789        mod my_module;
790        fn aux_func;
791        impl Person;
792    }
793
794    #[test]
795    fn export_test() {
796        test! {
797            use super::*;
798            // Call the exported functions through their generated C wrappers.
799            unsafe {
800                wrap__inttypes(
801                    Robj::from(1).get(),
802                    Robj::from(2).get(),
803                    Robj::from(3).get(),
804                    Robj::from(4).get(),
805                    Robj::from(5).get(),
806                    Robj::from(6).get(),
807                    Robj::from(7).get(),
808                    Robj::from(8).get(),
809                );
810                wrap__inttypes(
811                    Robj::from(1.).get(),
812                    Robj::from(2.).get(),
813                    Robj::from(3.).get(),
814                    Robj::from(4.).get(),
815                    Robj::from(5.).get(),
816                    Robj::from(6.).get(),
817                    Robj::from(7.).get(),
818                    Robj::from(8.).get(),
819                );
820                wrap__floattypes(Robj::from(1.).get(), Robj::from(2.).get());
821                wrap__floattypes(Robj::from(1).get(), Robj::from(2).get());
822                wrap__strtypes(Robj::from("abc").get(), Robj::from("def").get());
823                wrap__vectortypes(
824                    Robj::from(&[1, 2, 3] as &[i32]).get(),
825                    Robj::from(&[4., 5., 6.] as &[f64]).get(),
826                );
827                wrap__robjtype(Robj::from(1).get());
828
829                // General integer types.
830                assert_eq!(Robj::from_sexp(wrap__return_u8()), Robj::from(123_u8));
831                assert_eq!(Robj::from_sexp(wrap__return_u16()), Robj::from(123));
832                assert_eq!(Robj::from_sexp(wrap__return_u32()), Robj::from(123.));
833                assert_eq!(Robj::from_sexp(wrap__return_u64()), Robj::from(123.));
834                assert_eq!(Robj::from_sexp(wrap__return_i8()), Robj::from(123));
835                assert_eq!(Robj::from_sexp(wrap__return_i16()), Robj::from(123));
836                assert_eq!(Robj::from_sexp(wrap__return_i32()), Robj::from(123));
837                assert_eq!(Robj::from_sexp(wrap__return_i64()), Robj::from(123.));
838
839                // Floating point types.
840                assert_eq!(Robj::from_sexp(wrap__return_f32()), Robj::from(123.));
841                assert_eq!(Robj::from_sexp(wrap__return_f64()), Robj::from(123.));
842            }
843        }
844    }
845
846    #[test]
847    fn class_wrapper_test() {
848        test! {
849            let mut person = Person::new();
850            person.set_name("fred");
851            let robj = r!(person);
852            assert_eq!(robj.check_external_ptr_type::<Person>(), true);
853            let person2 = <&Person>::try_from(&robj).unwrap();
854            assert_eq!(person2.name(), "fred");
855        }
856    }
857
858    #[test]
859    fn slice_test() {
860        test! {
861            unsafe {
862                // #[extendr]
863                // pub fn f64_slice(x: &[f64]) -> &[f64] { x }
864
865                let robj = r!([1., 2., 3.]);
866                assert_eq!(Robj::from_sexp(wrap__f64_slice(robj.get())), robj);
867
868                // #[extendr]
869                // pub fn i32_slice(x: &[i32]) -> &[i32] { x }
870
871                let robj = r!([1, 2, 3]);
872                assert_eq!(Robj::from_sexp(wrap__i32_slice(robj.get())), robj);
873
874                // #[extendr]
875                // pub fn bool_slice(x: &[Rbool]) -> &[Rbool] { x }
876
877                let robj = r!([TRUE, FALSE, TRUE]);
878                assert_eq!(Robj::from_sexp(wrap__bool_slice(robj.get())), robj);
879
880                // #[extendr]
881                // pub fn f64_iter(x: Doubles) -> Doubles { x }
882
883                let robj = r!([1., 2., 3.]);
884                assert_eq!(Robj::from_sexp(wrap__f64_iter(robj.get())), robj);
885
886                // #[extendr]
887                // pub fn i32_iter(x: Integers) -> Integers { x }
888
889                let robj = r!([1, 2, 3]);
890                assert_eq!(Robj::from_sexp(wrap__i32_iter(robj.get())), robj);
891
892                // #[extendr]
893                // pub fn bool_iter(x: Logicals) -> Logicals { x }
894
895                // TODO: reinstate this test.
896                // let robj = r!([TRUE, FALSE, TRUE]);
897                // assert_eq!(Robj::from_sexp(wrap__bool_iter(robj.get())), robj);
898
899                // #[extendr]
900                // pub fn symbol(x: Symbol) -> Symbol { x }
901
902                let robj = sym!(fred);
903                assert_eq!(Robj::from_sexp(wrap__symbol(robj.get())), robj);
904
905                // #[extendr]
906                // pub fn matrix(x: Matrix<&[f64]>) -> Matrix<&[f64]> { x }
907
908                let m = RMatrix::new_matrix(1, 2, |r, c| if r == c {1.0} else {0.});
909                let robj = r!(m);
910                assert_eq!(Robj::from_sexp(wrap__matrix(robj.get())), robj);
911            }
912        }
913    }
914
915    #[test]
916    fn r_output_test() {
917        // R equivalent
918        // > txt_con <- textConnection("test_con", open = "w")
919        // > sink(txt_con)
920        // > cat("Hello world")
921        // > sink()
922        // > close(txt_con)
923        // > expect_equal(test_con, "Hello world")
924        //
925
926        test! {
927            let txt_con = R!(r#"textConnection("test_con", open = "w")"#).unwrap();
928            call!("sink", &txt_con).unwrap();
929            rprintln!("Hello world %%!"); //%% checks printf formatting is off, yields one % if on
930            call!("sink").unwrap();
931            call!("close", &txt_con).unwrap();
932            let result = R!("test_con").unwrap();
933            assert_eq!(result, r!("Hello world %%!"));
934        }
935    }
936
937    #[test]
938    fn test_na_str() {
939        assert_ne!(<&str>::na().as_ptr(), "NA".as_ptr());
940        assert_eq!(<&str>::na(), "NA");
941        assert!(!"NA".is_na());
942        assert!(<&str>::na().is_na());
943    }
944
945    #[test]
946    fn metadata_test() {
947        test! {
948            // Rust interface.
949            let metadata = get_my_module_metadata();
950            assert_eq!(metadata.functions[0].doc, " comment #1\n comment #2\n\n        comment #3\n        comment #4\n    *\n aux_func doc comment.");
951            assert_eq!(metadata.functions[0].rust_name, "aux_func");
952            assert_eq!(metadata.functions[0].mod_name, "aux_func");
953            assert_eq!(metadata.functions[0].r_name, "aux_func");
954            assert_eq!(metadata.functions[0].args[0].name, "_person");
955            assert_eq!(metadata.functions[1].rust_name, "get_my_module_metadata");
956            assert_eq!(metadata.impls[0].name, "Person");
957            assert_eq!(metadata.impls[0].methods.len(), 3);
958
959            // R interface
960            let robj = unsafe { Robj::from_sexp(wrap__get_my_module_metadata()) };
961            let functions = robj.dollar("functions").unwrap();
962            let impls = robj.dollar("impls").unwrap();
963            assert_eq!(functions.len(), 3);
964            assert_eq!(impls.len(), 1);
965        }
966    }
967
968    #[test]
969    fn pairlist_macro_works() {
970        test! {
971            assert_eq!(pairlist!(1, 2, 3), Pairlist::from_pairs(&[("", 1), ("", 2), ("", 3)]));
972            assert_eq!(pairlist!(a=1, 2, 3), Pairlist::from_pairs(&[("a", 1), ("", 2), ("", 3)]));
973            assert_eq!(pairlist!(1, b=2, 3), Pairlist::from_pairs(&[("", 1), ("b", 2), ("", 3)]));
974            assert_eq!(pairlist!(a=1, b=2, c=3), Pairlist::from_pairs(&[("a", 1), ("b", 2), ("c", 3)]));
975            assert_eq!(pairlist!(a=NULL), Pairlist::from_pairs(&[("a", ())]));
976            assert_eq!(pairlist!(), Pairlist::from(()));
977        }
978    }
979
980    #[test]
981    fn big_r_macro_works() {
982        test! {
983            assert_eq!(R!("1")?, r!(1.0));
984            assert_eq!(R!(r"1")?, r!(1.0));
985            assert_eq!(R!(r"
986                x <- 1
987                x
988            ")?, r!(1.0));
989            assert_eq!(R!(r"
990                x <- {{ 1.0 }}
991                x
992            ")?, r!(1.0));
993            assert_eq!(R!(r"
994                x <- {{ (0..4).collect::<Robj>() }}
995                x
996            ")?, r!([0, 1, 2, 3]));
997            assert_eq!(R!(r#"
998                x <- "hello"
999                x
1000            "#)?, r!("hello"));
1001            assert_eq!(Rraw!(r"
1002                x <- {{ 1 }}
1003                x
1004            ")?, r!(1.0));
1005        }
1006    }
1007}