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//! - `graphics`: provides the functionality to control or implement graphics devices.
295//! - `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.
296//! - `faer`: provides conversion between R's matrices and [`faer`](https://docs.rs/faer/latest/faer/).
297//!
298//! extendr-api supports three ways of returning a Result<T,E> to R.
299//! Only one behavior feature can be enabled at a time.
300//! - `result_panic`: Default behavior, return `Ok` as is, panic! on any `Err`
301//!
302//! Default behavior can be overridden by specifying `extend_api` features, i.e. `extendr-api = {..., default-features = false, features= ["result_condition"]}`
303//! These features are experimental and are subject to change.
304//! - `result_list`: return `Ok` as `list(ok=?, err=NULL)` or `Err` `list(ok=NULL, err=?)`
305//! - `result_condition`: return `Ok` as is or `Err` as $value in an R error condition.
306#![doc(
307 html_logo_url = "https://raw.githubusercontent.com/extendr/extendr/main/extendr-logo-256.png"
308)]
309
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;
330
331#[cfg(feature = "serde")]
332pub mod serializer;
333
334#[cfg(feature = "serde")]
335pub mod deserializer;
336
337#[cfg(feature = "graphics")]
338pub mod graphics;
339
340pub(crate) mod conversions;
341
342//////////////////////////////////////////////////
343// Note these pub use statements are deprecated
344//
345// `use extendr_api::prelude::*;`
346//
347// instead.
348
349pub use error::*;
350pub use functions::*;
351pub use lang_macros::*;
352pub use na::*;
353pub use robj::*;
354pub use thread_safety::{catch_r_error, single_threaded, throw_r_error};
355pub use wrapper::*;
356
357pub use extendr_macros::*;
358
359use extendr_ffi::SEXPTYPE;
360use scalar::Rbool;
361
362//////////////////////////////////////////////////
363
364/// TRUE value eg. `r!(TRUE)`
365pub const TRUE: Rbool = Rbool::true_value();
366
367/// FALSE value eg. `r!(FALSE)`
368pub const FALSE: Rbool = Rbool::false_value();
369
370/// NULL value eg. `r!(NULL)`
371pub const NULL: () = ();
372
373/// NA value for integers eg. `r!(NA_INTEGER)`
374pub const NA_INTEGER: Option<i32> = None;
375
376/// NA value for real values eg. `r!(NA_REAL)`
377pub const NA_REAL: Option<f64> = None;
378
379/// NA value for strings. `r!(NA_STRING)`
380pub const NA_STRING: Option<&str> = None;
381
382/// NA value for logical. `r!(NA_LOGICAL)`
383pub const NA_LOGICAL: Rbool = Rbool::na_value();
384
385/// This is needed for the generation of wrappers.
386#[doc(hidden)]
387pub use extendr_ffi::DllInfo;
388
389/// This is necessary for `#[extendr]`-impl
390#[doc(hidden)]
391pub use extendr_ffi::R_ExternalPtrAddr;
392
393/// This is used in `#[extendr(use_rng = true)]` on `fn`-items.
394#[doc(hidden)]
395pub use extendr_ffi::GetRNGstate;
396
397/// This is used in `#[extendr(use_rng = true)]` on `fn`-items.
398#[doc(hidden)]
399pub use extendr_ffi::PutRNGstate;
400
401#[doc(hidden)]
402pub use extendr_ffi::SEXP;
403
404pub use metadata::Metadata;
405
406#[doc(hidden)]
407pub struct CallMethod {
408 pub call_symbol: std::ffi::CString,
409 pub func_ptr: *const u8,
410 pub num_args: i32,
411}
412
413unsafe fn make_method_def(
414 cstrings: &mut Vec<std::ffi::CString>,
415 rmethods: &mut Vec<extendr_ffi::R_CallMethodDef>,
416 func: &metadata::Func,
417 wrapped_name: &str,
418) {
419 cstrings.push(std::ffi::CString::new(wrapped_name).unwrap());
420 rmethods.push(extendr_ffi::R_CallMethodDef {
421 name: cstrings.last().unwrap().as_ptr(),
422 fun: Some(std::mem::transmute::<
423 *const u8,
424 unsafe extern "C" fn() -> *mut std::ffi::c_void,
425 >(func.func_ptr)),
426 numArgs: func.args.len() as i32,
427 });
428}
429
430// Internal function used to implement the .Call interface.
431// This is called from the code generated by the #[extendr] attribute.
432#[doc(hidden)]
433pub unsafe fn register_call_methods(info: *mut extendr_ffi::DllInfo, metadata: Metadata) {
434 let mut rmethods = Vec::new();
435 let mut cstrings = Vec::new();
436 for func in metadata.functions {
437 make_method_def(&mut cstrings, &mut rmethods, &func, func.c_name);
438 }
439
440 for imp in metadata.impls {
441 for func in imp.methods {
442 make_method_def(&mut cstrings, &mut rmethods, &func, func.c_name);
443 }
444 }
445
446 rmethods.push(extendr_ffi::R_CallMethodDef {
447 name: std::ptr::null(),
448 fun: None,
449 numArgs: 0,
450 });
451
452 extendr_ffi::R_registerRoutines(
453 info,
454 std::ptr::null(),
455 rmethods.as_ptr(),
456 std::ptr::null(),
457 std::ptr::null(),
458 );
459
460 // This seems to allow both symbols and strings,
461 extendr_ffi::R_useDynamicSymbols(info, extendr_ffi::Rboolean::FALSE);
462 extendr_ffi::R_forceSymbols(info, extendr_ffi::Rboolean::FALSE);
463}
464
465/// Type of R objects used by [Robj::rtype].
466#[derive(Debug, PartialEq)]
467pub enum Rtype {
468 Null, // NILSXP
469 Symbol, // SYMSXP
470 Pairlist, // LISTSXP
471 Function, // CLOSXP
472 Environment, // ENVSXP
473 Promise, // PROMSXP
474 Language, // LANGSXP
475 Special, // SPECIALSXP
476 Builtin, // BUILTINSXP
477 Rstr, // CHARSXP
478 Logicals, // LGLSXP
479 Integers, // INTSXP
480 Doubles, // REALSXP
481 Complexes, // CPLXSXP
482 Strings, // STRSXP
483 Dot, // DOTSXP
484 Any, // ANYSXP
485 List, // VECSXP
486 Expressions, // EXPRSXP
487 Bytecode, // BCODESXP
488 ExternalPtr, // EXTPTRSXP
489 WeakRef, // WEAKREFSXP
490 Raw, // RAWSXP
491 S4, // S4SXP
492 Unknown,
493}
494
495/// Enum use to unpack R objects into their specialist wrappers.
496// Todo: convert all Robj types to wrappers.
497// Note: this only works if the wrappers are all just SEXPs.
498#[derive(Debug, PartialEq)]
499pub enum Rany<'a> {
500 Null(&'a Robj), // NILSXP
501 Symbol(&'a Symbol), // SYMSXP
502 Pairlist(&'a Pairlist), // LISTSXP
503 Function(&'a Function), // CLOSXP
504 Environment(&'a Environment), // ENVSXP
505 Promise(&'a Promise), // PROMSXP
506 Language(&'a Language), // LANGSXP
507 Special(&'a Primitive), // SPECIALSXP
508 Builtin(&'a Primitive), // BUILTINSXP
509 Rstr(&'a Rstr), // CHARSXP
510 Logicals(&'a Logicals), // LGLSXP
511 Integers(&'a Integers), // INTSXP
512 Doubles(&'a Doubles), // REALSXP
513 Complexes(&'a Complexes), // CPLXSXP
514 Strings(&'a Strings), // STRSXP
515 Dot(&'a Robj), // DOTSXP
516 Any(&'a Robj), // ANYSXP
517 List(&'a List), // VECSXP
518 Expressions(&'a Expressions), // EXPRSXP
519 Bytecode(&'a Robj), // BCODESXP
520 ExternalPtr(&'a Robj), // EXTPTRSXP
521 WeakRef(&'a Robj), // WEAKREFSXP
522 Raw(&'a Raw), // RAWSXP
523 S4(&'a S4), // S4SXP
524 Unknown(&'a Robj),
525}
526
527/// Convert extendr's Rtype to R's SEXPTYPE.
528/// Panics if the type is Unknown.
529pub fn rtype_to_sxp(rtype: Rtype) -> SEXPTYPE {
530 use extendr_ffi::SEXPTYPE;
531 match rtype {
532 Rtype::Null => SEXPTYPE::NILSXP,
533 Rtype::Symbol => SEXPTYPE::SYMSXP,
534 Rtype::Pairlist => SEXPTYPE::LISTSXP,
535 Rtype::Function => SEXPTYPE::CLOSXP,
536 Rtype::Environment => SEXPTYPE::ENVSXP,
537 Rtype::Promise => SEXPTYPE::PROMSXP,
538 Rtype::Language => SEXPTYPE::LANGSXP,
539 Rtype::Special => SEXPTYPE::SPECIALSXP,
540 Rtype::Builtin => SEXPTYPE::BUILTINSXP,
541 Rtype::Rstr => SEXPTYPE::CHARSXP,
542 Rtype::Logicals => SEXPTYPE::LGLSXP,
543 Rtype::Integers => SEXPTYPE::INTSXP,
544 Rtype::Doubles => SEXPTYPE::REALSXP,
545 Rtype::Complexes => SEXPTYPE::CPLXSXP,
546 Rtype::Strings => SEXPTYPE::STRSXP,
547 Rtype::Dot => SEXPTYPE::DOTSXP,
548 Rtype::Any => SEXPTYPE::ANYSXP,
549 Rtype::List => SEXPTYPE::VECSXP,
550 Rtype::Expressions => SEXPTYPE::EXPRSXP,
551 Rtype::Bytecode => SEXPTYPE::BCODESXP,
552 Rtype::ExternalPtr => SEXPTYPE::EXTPTRSXP,
553 Rtype::WeakRef => SEXPTYPE::WEAKREFSXP,
554 Rtype::Raw => SEXPTYPE::RAWSXP,
555 #[cfg(not(use_objsxp))]
556 Rtype::S4 => SEXPTYPE::S4SXP,
557 #[cfg(use_objsxp)]
558 Rtype::S4 => SEXPTYPE::OBJSXP,
559 Rtype::Unknown => panic!("attempt to use Unknown Rtype"),
560 }
561}
562
563/// Convert R's SEXPTYPE to extendr's Rtype.
564pub fn sxp_to_rtype(sxptype: SEXPTYPE) -> Rtype {
565 match sxptype {
566 SEXPTYPE::NILSXP => Rtype::Null,
567 SEXPTYPE::SYMSXP => Rtype::Symbol,
568 SEXPTYPE::LISTSXP => Rtype::Pairlist,
569 SEXPTYPE::CLOSXP => Rtype::Function,
570 SEXPTYPE::ENVSXP => Rtype::Environment,
571 SEXPTYPE::PROMSXP => Rtype::Promise,
572 SEXPTYPE::LANGSXP => Rtype::Language,
573 SEXPTYPE::SPECIALSXP => Rtype::Special,
574 SEXPTYPE::BUILTINSXP => Rtype::Builtin,
575 SEXPTYPE::CHARSXP => Rtype::Rstr,
576 SEXPTYPE::LGLSXP => Rtype::Logicals,
577 SEXPTYPE::INTSXP => Rtype::Integers,
578 SEXPTYPE::REALSXP => Rtype::Doubles,
579 SEXPTYPE::CPLXSXP => Rtype::Complexes,
580 SEXPTYPE::STRSXP => Rtype::Strings,
581 SEXPTYPE::DOTSXP => Rtype::Dot,
582 SEXPTYPE::ANYSXP => Rtype::Any,
583 SEXPTYPE::VECSXP => Rtype::List,
584 SEXPTYPE::EXPRSXP => Rtype::Expressions,
585 SEXPTYPE::BCODESXP => Rtype::Bytecode,
586 SEXPTYPE::EXTPTRSXP => Rtype::ExternalPtr,
587 SEXPTYPE::WEAKREFSXP => Rtype::WeakRef,
588 SEXPTYPE::RAWSXP => Rtype::Raw,
589 #[cfg(not(use_objsxp))]
590 SEXPTYPE::S4SXP => Rtype::S4,
591 #[cfg(use_objsxp)]
592 SEXPTYPE::OBJSXP => Rtype::S4,
593 _ => Rtype::Unknown,
594 }
595}
596
597const PRINTF_NO_FMT_CSTRING: &[std::os::raw::c_char] = &[37, 115, 0]; // same as "%s\0"
598#[doc(hidden)]
599pub fn print_r_output<T: Into<Vec<u8>>>(s: T) {
600 let cs = std::ffi::CString::new(s).expect("NulError");
601 unsafe {
602 extendr_ffi::Rprintf(PRINTF_NO_FMT_CSTRING.as_ptr(), cs.as_ptr());
603 }
604}
605
606#[doc(hidden)]
607pub fn print_r_error<T: Into<Vec<u8>>>(s: T) {
608 let cs = std::ffi::CString::new(s).expect("NulError");
609 unsafe {
610 extendr_ffi::REprintf(PRINTF_NO_FMT_CSTRING.as_ptr(), cs.as_ptr());
611 }
612}
613
614#[cfg(test)]
615mod tests {
616 use super::prelude::*;
617 use crate as extendr_api;
618
619 use extendr_macros::extendr;
620 use extendr_macros::extendr_module;
621 use extendr_macros::pairlist;
622
623 #[allow(clippy::too_many_arguments)]
624 #[extendr]
625 pub fn inttypes(a: i8, b: u8, c: i16, d: u16, e: i32, f: u32, g: i64, h: u64) {
626 assert_eq!(a, 1);
627 assert_eq!(b, 2);
628 assert_eq!(c, 3);
629 assert_eq!(d, 4);
630 assert_eq!(e, 5);
631 assert_eq!(f, 6);
632 assert_eq!(g, 7);
633 assert_eq!(h, 8);
634 }
635
636 #[extendr]
637 pub fn floattypes(a: f32, b: f64) {
638 assert_eq!(a, 1.);
639 assert_eq!(b, 2.);
640 }
641
642 #[extendr]
643 pub fn strtypes(a: &str, b: String) {
644 assert_eq!(a, "abc");
645 assert_eq!(b, "def");
646 }
647
648 #[extendr]
649 pub fn vectortypes(a: Vec<i32>, b: Vec<f64>) {
650 assert_eq!(a, [1, 2, 3]);
651 assert_eq!(b, [4., 5., 6.]);
652 }
653
654 #[extendr]
655 pub fn robjtype(a: Robj) {
656 assert_eq!(a, Robj::from(1))
657 }
658
659 #[extendr]
660 pub fn return_u8() -> u8 {
661 123
662 }
663
664 #[extendr]
665 pub fn return_u16() -> u16 {
666 123
667 }
668
669 #[extendr]
670 pub fn return_u32() -> u32 {
671 123
672 }
673
674 #[extendr]
675 pub fn return_u64() -> u64 {
676 123
677 }
678
679 #[extendr]
680 pub fn return_i8() -> i8 {
681 123
682 }
683
684 #[extendr]
685 pub fn return_i16() -> i16 {
686 123
687 }
688
689 #[extendr]
690 pub fn return_i32() -> i32 {
691 123
692 }
693
694 #[extendr]
695 pub fn return_i64() -> i64 {
696 123
697 }
698
699 #[extendr]
700 pub fn return_f32() -> f32 {
701 123.
702 }
703
704 #[extendr]
705 pub fn return_f64() -> f64 {
706 123.
707 }
708
709 #[extendr]
710 pub fn f64_slice(x: &[f64]) -> &[f64] {
711 x
712 }
713
714 #[extendr]
715 pub fn i32_slice(x: &[i32]) -> &[i32] {
716 x
717 }
718
719 #[extendr]
720 pub fn bool_slice(x: &[Rbool]) -> &[Rbool] {
721 x
722 }
723
724 #[extendr]
725 pub fn f64_iter(x: Doubles) -> Doubles {
726 x
727 }
728
729 #[extendr]
730 pub fn i32_iter(x: Integers) -> Integers {
731 x
732 }
733
734 // #[extendr]
735 // pub fn bool_iter(x: Logicals) -> Logicals {
736 // x
737 // }
738
739 #[extendr]
740 pub fn symbol(x: Symbol) -> Symbol {
741 x
742 }
743
744 #[extendr]
745 pub fn matrix(x: RMatrix<f64>) -> RMatrix<f64> {
746 x
747 }
748
749 #[extendr]
750 struct Person {
751 pub name: String,
752 }
753
754 #[extendr]
755 /// impl comment.
756 impl Person {
757 fn new() -> Self {
758 Self {
759 name: "".to_string(),
760 }
761 }
762
763 fn set_name(&mut self, name: &str) {
764 self.name = name.to_string();
765 }
766
767 fn name(&self) -> &str {
768 self.name.as_str()
769 }
770 }
771
772 // see metadata_test for the following comments.
773
774 /// comment #1
775 /// comment #2
776 /**
777 comment #3
778 comment #4
779 **/
780 #[extendr]
781 /// aux_func doc comment.
782 fn aux_func(_person: &Person) {}
783
784 // Macro to generate exports
785 extendr_module! {
786 mod my_module;
787 fn aux_func;
788 impl Person;
789 }
790
791 #[test]
792 fn export_test() {
793 test! {
794 use super::*;
795 // Call the exported functions through their generated C wrappers.
796 unsafe {
797 wrap__inttypes(
798 Robj::from(1).get(),
799 Robj::from(2).get(),
800 Robj::from(3).get(),
801 Robj::from(4).get(),
802 Robj::from(5).get(),
803 Robj::from(6).get(),
804 Robj::from(7).get(),
805 Robj::from(8).get(),
806 );
807 wrap__inttypes(
808 Robj::from(1.).get(),
809 Robj::from(2.).get(),
810 Robj::from(3.).get(),
811 Robj::from(4.).get(),
812 Robj::from(5.).get(),
813 Robj::from(6.).get(),
814 Robj::from(7.).get(),
815 Robj::from(8.).get(),
816 );
817 wrap__floattypes(Robj::from(1.).get(), Robj::from(2.).get());
818 wrap__floattypes(Robj::from(1).get(), Robj::from(2).get());
819 wrap__strtypes(Robj::from("abc").get(), Robj::from("def").get());
820 wrap__vectortypes(
821 Robj::from(&[1, 2, 3] as &[i32]).get(),
822 Robj::from(&[4., 5., 6.] as &[f64]).get(),
823 );
824 wrap__robjtype(Robj::from(1).get());
825
826 // General integer types.
827 assert_eq!(Robj::from_sexp(wrap__return_u8()), Robj::from(123_u8));
828 assert_eq!(Robj::from_sexp(wrap__return_u16()), Robj::from(123));
829 assert_eq!(Robj::from_sexp(wrap__return_u32()), Robj::from(123.));
830 assert_eq!(Robj::from_sexp(wrap__return_u64()), Robj::from(123.));
831 assert_eq!(Robj::from_sexp(wrap__return_i8()), Robj::from(123));
832 assert_eq!(Robj::from_sexp(wrap__return_i16()), Robj::from(123));
833 assert_eq!(Robj::from_sexp(wrap__return_i32()), Robj::from(123));
834 assert_eq!(Robj::from_sexp(wrap__return_i64()), Robj::from(123.));
835
836 // Floating point types.
837 assert_eq!(Robj::from_sexp(wrap__return_f32()), Robj::from(123.));
838 assert_eq!(Robj::from_sexp(wrap__return_f64()), Robj::from(123.));
839 }
840 }
841 }
842
843 #[test]
844 fn class_wrapper_test() {
845 test! {
846 let mut person = Person::new();
847 person.set_name("fred");
848 let robj = r!(person);
849 assert_eq!(robj.check_external_ptr_type::<Person>(), true);
850 let person2 = <&Person>::try_from(&robj).unwrap();
851 assert_eq!(person2.name(), "fred");
852 }
853 }
854
855 #[test]
856 fn slice_test() {
857 test! {
858 unsafe {
859 // #[extendr]
860 // pub fn f64_slice(x: &[f64]) -> &[f64] { x }
861
862 let robj = r!([1., 2., 3.]);
863 assert_eq!(Robj::from_sexp(wrap__f64_slice(robj.get())), robj);
864
865 // #[extendr]
866 // pub fn i32_slice(x: &[i32]) -> &[i32] { x }
867
868 let robj = r!([1, 2, 3]);
869 assert_eq!(Robj::from_sexp(wrap__i32_slice(robj.get())), robj);
870
871 // #[extendr]
872 // pub fn bool_slice(x: &[Rbool]) -> &[Rbool] { x }
873
874 let robj = r!([TRUE, FALSE, TRUE]);
875 assert_eq!(Robj::from_sexp(wrap__bool_slice(robj.get())), robj);
876
877 // #[extendr]
878 // pub fn f64_iter(x: Doubles) -> Doubles { x }
879
880 let robj = r!([1., 2., 3.]);
881 assert_eq!(Robj::from_sexp(wrap__f64_iter(robj.get())), robj);
882
883 // #[extendr]
884 // pub fn i32_iter(x: Integers) -> Integers { x }
885
886 let robj = r!([1, 2, 3]);
887 assert_eq!(Robj::from_sexp(wrap__i32_iter(robj.get())), robj);
888
889 // #[extendr]
890 // pub fn bool_iter(x: Logicals) -> Logicals { x }
891
892 // TODO: reinstate this test.
893 // let robj = r!([TRUE, FALSE, TRUE]);
894 // assert_eq!(Robj::from_sexp(wrap__bool_iter(robj.get())), robj);
895
896 // #[extendr]
897 // pub fn symbol(x: Symbol) -> Symbol { x }
898
899 let robj = sym!(fred);
900 assert_eq!(Robj::from_sexp(wrap__symbol(robj.get())), robj);
901
902 // #[extendr]
903 // pub fn matrix(x: Matrix<&[f64]>) -> Matrix<&[f64]> { x }
904
905 let m = RMatrix::new_matrix(1, 2, |r, c| if r == c {1.0} else {0.});
906 let robj = r!(m);
907 assert_eq!(Robj::from_sexp(wrap__matrix(robj.get())), robj);
908 }
909 }
910 }
911
912 #[test]
913 fn r_output_test() {
914 // R equivalent
915 // > txt_con <- textConnection("test_con", open = "w")
916 // > sink(txt_con)
917 // > cat("Hello world")
918 // > sink()
919 // > close(txt_con)
920 // > expect_equal(test_con, "Hello world")
921 //
922
923 test! {
924 let txt_con = R!(r#"textConnection("test_con", open = "w")"#).unwrap();
925 call!("sink", &txt_con).unwrap();
926 rprintln!("Hello world %%!"); //%% checks printf formatting is off, yields one % if on
927 call!("sink").unwrap();
928 call!("close", &txt_con).unwrap();
929 let result = R!("test_con").unwrap();
930 assert_eq!(result, r!("Hello world %%!"));
931 }
932 }
933
934 #[test]
935 fn test_na_str() {
936 assert_ne!(<&str>::na().as_ptr(), "NA".as_ptr());
937 assert_eq!(<&str>::na(), "NA");
938 assert!(!"NA".is_na());
939 assert!(<&str>::na().is_na());
940 }
941
942 #[test]
943 fn metadata_test() {
944 test! {
945 // Rust interface.
946 let metadata = get_my_module_metadata();
947 assert_eq!(metadata.functions[0].doc, " comment #1\n comment #2\n\n comment #3\n comment #4\n *\n aux_func doc comment.");
948 assert_eq!(metadata.functions[0].rust_name, "aux_func");
949 assert_eq!(metadata.functions[0].mod_name, "aux_func");
950 assert_eq!(metadata.functions[0].r_name, "aux_func");
951 assert_eq!(metadata.functions[0].args[0].name, "_person");
952 assert_eq!(metadata.functions[1].rust_name, "get_my_module_metadata");
953 assert_eq!(metadata.impls[0].name, "Person");
954 assert_eq!(metadata.impls[0].methods.len(), 3);
955
956 // R interface
957 let robj = unsafe { Robj::from_sexp(wrap__get_my_module_metadata()) };
958 let functions = robj.dollar("functions").unwrap();
959 let impls = robj.dollar("impls").unwrap();
960 assert_eq!(functions.len(), 3);
961 assert_eq!(impls.len(), 1);
962 }
963 }
964
965 #[test]
966 fn pairlist_macro_works() {
967 test! {
968 assert_eq!(pairlist!(1, 2, 3), Pairlist::from_pairs(&[("", 1), ("", 2), ("", 3)]));
969 assert_eq!(pairlist!(a=1, 2, 3), Pairlist::from_pairs(&[("a", 1), ("", 2), ("", 3)]));
970 assert_eq!(pairlist!(1, b=2, 3), Pairlist::from_pairs(&[("", 1), ("b", 2), ("", 3)]));
971 assert_eq!(pairlist!(a=1, b=2, c=3), Pairlist::from_pairs(&[("a", 1), ("b", 2), ("c", 3)]));
972 assert_eq!(pairlist!(a=NULL), Pairlist::from_pairs(&[("a", ())]));
973 assert_eq!(pairlist!(), Pairlist::from(()));
974 }
975 }
976
977 #[test]
978 fn big_r_macro_works() {
979 test! {
980 assert_eq!(R!("1")?, r!(1.0));
981 assert_eq!(R!(r"1")?, r!(1.0));
982 assert_eq!(R!(r"
983 x <- 1
984 x
985 ")?, r!(1.0));
986 assert_eq!(R!(r"
987 x <- {{ 1.0 }}
988 x
989 ")?, r!(1.0));
990 assert_eq!(R!(r"
991 x <- {{ (0..4).collect_robj() }}
992 x
993 ")?, r!([0, 1, 2, 3]));
994 assert_eq!(R!(r#"
995 x <- "hello"
996 x
997 "#)?, r!("hello"));
998 assert_eq!(Rraw!(r"
999 x <- {{ 1 }}
1000 x
1001 ")?, r!(1.0));
1002 }
1003 }
1004}