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