aorist_extendr_api/
lib.rs

1//!
2//! A safe and user friendly R extension interface.
3//!
4//! * Build rust extensions to R.
5//! * Convert R packages to Rust crates.
6//!
7//! This library aims to provide an interface that will be familiar to
8//! first-time users of Rust or indeed any compiled language.
9//!
10//! See [Robj] for much of the content of this crate.
11//! [Robj] provides a safe wrapper for the R object type.
12//!
13//! Use attributes and macros to export to R.
14//! ```ignore
15//! use extendr_api::prelude::*;
16//! // Export a function or impl to R.
17//! #[extendr]
18//! fn fred(a: i32) -> i32 {
19//!     a + 1
20//! }
21//!
22//! // define exports using extendr_module
23//! extendr_module! {
24//!    mod mymodule;
25//!    fn fred;
26//! }
27//!
28//! ```
29//!
30//! In R:
31//!
32//! ```ignore
33//! result <- fred(1)
34//! ```
35//!
36//! [Robj] is a wrapper for R objects.
37//! The r!() and R!() macros let you build R objects
38//! using Rust and R syntax respectively.
39//! ```
40//! use extendr_api::prelude::*;
41//! test! {
42//!     // An R object with a single string "hello"
43//!     let character = r!("hello");
44//!     let character = r!(["hello", "goodbye"]);
45//!
46//!     // An R integer object with a single number 1L.
47//!     // Note that in Rust, 1 is an integer and 1.0 is a real.
48//!     let integer = r!(1);
49//!
50//!     // An R real object with a single number 1.
51//!     // Note that in R, 1 is a real and 1L is an integer.
52//!     let real = r!(1.0);
53//!
54//!     // An R real vector.
55//!     let real_vector = r!([1.0, 2.0]);
56//!     let real_vector = &[1.0, 2.0].iter().collect_robj();
57//!     let real_vector = r!(vec![1.0, 2.0]);
58//!
59//!     // An R function object.
60//!     let function = R!("function(x, y) { x + y }")?;
61//!
62//!     // A named list using the list! macro.
63//!     let list = list!(a = 1, b = 2);
64//!
65//!     // An unnamed list (of R objects) using the List wrapper.
66//!     let list = r!(List::from_values(vec![1, 2, 3]));
67//!     let list = r!(List::from_values(vec!["a", "b", "c"]));
68//!     let list = r!(List::from_values(&[r!("a"), r!(1), r!(2.0)]));
69//!
70//!     // A symbol
71//!     let sym = sym!(wombat);
72//!
73//!     // A R vector using collect_robj()
74//!     let vector = (0..3).map(|x| x * 10).collect_robj();
75//! }
76//! ```
77//!
78//! In Rust, we prefer to use iterators rather than loops.
79//!
80//! ```
81//! use extendr_api::prelude::*;
82//! test! {
83//!     // 1 ..= 100 is the same as 1:100
84//!     let res = r!(1 ..= 100);
85//!     assert_eq!(res, R!("1:100")?);
86//!
87//!     // Rust arrays are zero-indexed so it is more common to use 0 .. 100.
88//!     let res = r!(0 .. 100);
89//!     assert_eq!(res.len(), 100);
90//!
91//!     // Using map is a super fast way to generate vectors.
92//!     let iter = (0..3).map(|i| format!("fred{}", i));
93//!     let character = iter.collect_robj();
94//!     assert_eq!(character, r!(["fred0", "fred1", "fred2"]));
95//! }
96//! ```
97//!
98//! To index a vector, first convert it to a slice and then
99//! remember to use 0-based indexing. In Rust, going out of bounds
100//! will cause and error (a panic) unlike C++ which may crash.
101//! ```
102//! use extendr_api::prelude::*;
103//! test! {
104//!     let vals = r!([1.0, 2.0]);
105//!     let slice = vals.as_real_slice().ok_or("expected slice")?;
106//!     let one = slice[0];
107//!     let two = slice[1];
108//!     // let error = slice[2];
109//!     assert_eq!(one, 1.0);
110//!     assert_eq!(two, 2.0);
111//! }
112//! ```
113//!
114//! Much slower, but more general are these methods:
115//! ```
116//! use extendr_api::prelude::*;
117//! test! {
118//!     let vals = r!([1.0, 2.0, 3.0]);
119//!
120//!     // one-based indexing [[i]], returns an object.
121//!     assert_eq!(vals.index(1)?, r!(1.0));
122//!
123//!     // one-based slicing [x], returns an object.
124//!     assert_eq!(vals.slice(1..=2)?, r!([1.0, 2.0]));
125//!
126//!     // $ operator, returns an object
127//!     let list = list!(a = 1.0, b = "xyz");
128//!     assert_eq!(list.dollar("a")?, r!(1.0));
129//! }
130//! ```
131//!
132//! The [R!] macro lets you embed R code in Rust
133//! and takes Rust expressions in {{ }} pairs.
134//!
135//! The [Rraw!] macro will not expand the {{ }} pairs.
136//! ```
137//! use extendr_api::prelude::*;
138//! test! {
139//!     // The text "1 + 1" is parsed as R source code.
140//!     // The result is 1.0 + 1.0 in Rust.
141//!     assert_eq!(R!("1 + 1")?, r!(2.0));
142//!
143//!     let a = 1.0;
144//!     assert_eq!(R!("1 + {{a}}")?, r!(2.0));
145//!
146//!     assert_eq!(R!(r"
147//!         x <- {{ a }}
148//!         x + 1
149//!     ")?, r!(2.0));
150//!
151//!     assert_eq!(R!(r#"
152//!         x <- "hello"
153//!         x
154//!     "#)?, r!("hello"));
155//!
156//!     // Use the R meaning of {{ }} and do not expand.
157//!     assert_eq!(Rraw!(r"
158//!         x <- {{ 1 }}
159//!         x + 1
160//!     ")?, r!(2.0));
161//! }
162//! ```
163//!
164//! The [r!] macro converts a rust object to an R object
165//! and takes parameters.
166//! ```
167//! use extendr_api::prelude::*;
168//! test! {
169//!     // The text "1.0+1.0" is parsed as Rust source code.
170//!     let one = 1.0;
171//!     assert_eq!(r!(one+1.0), r!(2.0));
172//! }
173//! ```
174//!
175//! You can call R functions and primitives using the [call!] macro.
176//! ```
177//! use extendr_api::prelude::*;
178//! test! {
179//!
180//!     // As one R! macro call
181//!     let confint1 = R!(confint(lm(weight ~ group - 1, PlantGrowth)))?;
182//!
183//!     // As many parameterized calls.
184//!     let formula = call!("~", sym!(weight), lang!("-", sym!(group), 1))?;
185//!     let plant_growth = global!(PlantGrowth)?;
186//!     let model = call!("lm", formula, plant_growth)?;
187//!     let confint2 = call!("confint", model)?;
188//!
189//!     assert_eq!(confint1.as_real_vector(), confint2.as_real_vector());
190//! }
191//! ```
192//!
193//! Rust has a concept of "Owned" and "Borrowed" objects.
194//!
195//! Owned objects, such as [Vec] and [String] allocate memory
196//! which is released when the object lifetime ends.
197//!
198//! Borrowed objects such as &[i32] and &str are just pointers
199//! to annother object's memory and can't live longer than the
200//! object they reference.
201//!
202//! Borrowed objects are much faster than owned objects and use less
203//! memory but are used only for temporary access.
204//!
205//! When we take a slice of an R vector, for example, we need the
206//! original R object to be alive or the data will be corrupted.
207//!
208//! ```
209//! use extendr_api::prelude::*;
210//! test! {
211//!     // robj is an "Owned" object that controls the memory allocated.
212//!     let robj = r!([1, 2, 3]);
213//!
214//!     // Here slice is a "borrowed" reference to the bytes in robj.
215//!     // and cannot live longer than robj.
216//!     let slice = robj.as_integer_slice().ok_or("expected slice")?;
217//!     assert_eq!(slice.len(), 3);
218//! }
219//! ```
220
221#![doc(
222    html_logo_url = "https://raw.githubusercontent.com/extendr/extendr/master/extendr-logo-256.png"
223)]
224
225pub mod error;
226pub mod functions;
227pub mod iter;
228pub mod lang_macros;
229pub mod logical;
230pub mod metadata;
231pub mod ownership;
232pub mod prelude;
233pub mod rmacros;
234
235pub mod robj;
236pub mod thread_safety;
237pub mod wrapper;
238
239#[cfg(feature = "ndarray")]
240pub mod robj_ndarray;
241
242pub use std::convert::{TryFrom, TryInto};
243pub use std::ops::Deref;
244
245//////////////////////////////////////////////////
246// Note these pub use statements are deprectaed
247//
248// `use extendr_api::prelude::*;`
249//
250// instead.
251
252pub use error::*;
253pub use functions::*;
254pub use lang_macros::*;
255pub use logical::*;
256pub use rmacros::*;
257pub use robj::*;
258pub use thread_safety::{
259    catch_r_error, handle_panic, single_threaded, this_thread_id, throw_r_error,
260};
261pub use wrapper::*;
262
263#[cfg(feature = "ndarray")]
264pub use robj_ndarray::*;
265
266pub use aorist_extendr_macros::*;
267//////////////////////////////////////////////////
268
269/// TRUE value eg. `r!(TRUE)`
270pub const TRUE: Bool = Bool(1);
271
272/// FALSE value eg. `r!(FALSE)`
273pub const FALSE: Bool = Bool(0);
274
275/// NULL value eg. `r!(NULL)`
276pub const NULL: () = ();
277
278/// NA value for integers eg. `r!(NA_INTEGER)`
279pub const NA_INTEGER: Option<i32> = None;
280
281/// NA value for real values eg. `r!(NA_REAL)`
282pub const NA_REAL: Option<f64> = None;
283
284/// NA value for strings. `r!(NA_STRING)`
285pub const NA_STRING: Option<&str> = None;
286
287/// NA value for logical. `r!(NA_LOGICAL)`
288pub const NA_LOGICAL: Bool = Bool(std::i32::MIN);
289
290#[doc(hidden)]
291pub use std::collections::HashMap;
292
293#[doc(hidden)]
294pub use libR_sys::DllInfo;
295
296#[doc(hidden)]
297pub use libR_sys::SEXP;
298
299#[doc(hidden)]
300use libR_sys::*;
301
302#[doc(hidden)]
303use std::ffi::CString;
304
305pub use metadata::Metadata;
306
307#[doc(hidden)]
308pub struct CallMethod {
309    pub call_symbol: std::ffi::CString,
310    pub func_ptr: *const u8,
311    pub num_args: i32,
312}
313
314unsafe fn make_method_def(
315    cstrings: &mut Vec<std::ffi::CString>,
316    rmethods: &mut Vec<libR_sys::R_CallMethodDef>,
317    func: &metadata::Func,
318    wrapped_name: &str,
319) {
320    cstrings.push(std::ffi::CString::new(wrapped_name).unwrap());
321    rmethods.push(libR_sys::R_CallMethodDef {
322        name: cstrings.last().unwrap().as_ptr(),
323        fun: Some(std::mem::transmute(func.func_ptr)),
324        numArgs: func.args.len() as i32,
325    });
326}
327
328// Internal function used to implement the .Call interface.
329// This is called from the code generated by the #[extendr] attribute.
330#[doc(hidden)]
331pub unsafe fn register_call_methods(info: *mut libR_sys::DllInfo, metadata: Metadata) {
332    let mut rmethods = Vec::new();
333    let mut cstrings = Vec::new();
334    for func in metadata.functions {
335        let wrapped_name = format!("wrap__{}", func.name);
336        make_method_def(&mut cstrings, &mut rmethods, &func, wrapped_name.as_str());
337    }
338
339    for imp in metadata.impls {
340        for func in imp.methods {
341            let wrapped_name = format!("wrap__{}__{}", imp.name, func.name);
342            make_method_def(&mut cstrings, &mut rmethods, &func, wrapped_name.as_str());
343        }
344    }
345
346    rmethods.push(libR_sys::R_CallMethodDef {
347        name: std::ptr::null(),
348        fun: None,
349        numArgs: 0,
350    });
351
352    libR_sys::R_registerRoutines(
353        info,
354        std::ptr::null(),
355        rmethods.as_ptr(),
356        std::ptr::null(),
357        std::ptr::null(),
358    );
359
360    // This seems to allow both symbols and strings,
361    libR_sys::R_useDynamicSymbols(info, 0);
362    libR_sys::R_forceSymbols(info, 0);
363}
364
365/// Return true if this primitive is NA.
366pub trait IsNA {
367    fn is_na(&self) -> bool;
368}
369
370impl IsNA for f64 {
371    fn is_na(&self) -> bool {
372        unsafe { R_IsNA(*self) != 0 }
373    }
374}
375
376impl IsNA for i32 {
377    fn is_na(&self) -> bool {
378        *self == std::i32::MIN
379    }
380}
381
382impl IsNA for Bool {
383    fn is_na(&self) -> bool {
384        self.0 == std::i32::MIN
385    }
386}
387
388impl IsNA for &str {
389    /// Check for NA in a string by address.
390    fn is_na(&self) -> bool {
391        self.as_ptr() == na_str().as_ptr()
392    }
393}
394
395/// Type of R objects used by [Robj::rtype].
396#[derive(Debug, PartialEq)]
397pub enum RType {
398    Null,        // NILSXP
399    Symbol,      // SYMSXP
400    Pairlist,    // LISTSXP
401    Function,    // CLOSXP
402    Environment, // ENVSXP
403    Promise,     // PROMSXP
404    Language,    // LANGSXP
405    Special,     // SPECIALSXP
406    Builtin,     // BUILTINSXP
407    Character,   // CHARSXP
408    Logical,     // LGLSXP
409    Integer,     // INTSXP
410    Real,        // REALSXP
411    Complex,     // CPLXSXP
412    String,      // STRSXP
413    Dot,         // DOTSXP
414    Any,         // ANYSXP
415    List,        // VECSXP
416    Expression,  // EXPRSXP
417    Bytecode,    // BCODESXP
418    ExternalPtr, // EXTPTRSXP
419    WeakRef,     // WEAKREFSXP
420    Raw,         // RAWSXP
421    S4,          // S4SXP
422    Unknown,
423}
424
425#[doc(hidden)]
426pub fn print_r_output<T: Into<Vec<u8>>>(s: T) {
427    let cs = CString::new(s).expect("NulError");
428    unsafe {
429        Rprintf(cs.as_ptr());
430    }
431}
432
433#[doc(hidden)]
434pub fn print_r_error<T: Into<Vec<u8>>>(s: T) {
435    let cs = CString::new(s).expect("NulError");
436    unsafe {
437        REprintf(cs.as_ptr());
438    }
439}
440
441#[cfg(test)]
442mod tests {
443    use super::prelude::*;
444    use crate as extendr_api;
445    use std::collections::HashMap;
446
447    use extendr_macros::extendr;
448    use extendr_macros::extendr_module;
449    use extendr_macros::pairlist;
450
451    #[extendr]
452    pub fn inttypes(a: i8, b: u8, c: i16, d: u16, e: i32, f: u32, g: i64, h: u64) {
453        assert_eq!(a, 1);
454        assert_eq!(b, 2);
455        assert_eq!(c, 3);
456        assert_eq!(d, 4);
457        assert_eq!(e, 5);
458        assert_eq!(f, 6);
459        assert_eq!(g, 7);
460        assert_eq!(h, 8);
461    }
462
463    #[extendr]
464    pub fn floattypes(a: f32, b: f64) {
465        assert_eq!(a, 1.);
466        assert_eq!(b, 2.);
467    }
468
469    #[extendr]
470    pub fn strtypes(a: &str, b: String) {
471        assert_eq!(a, "abc");
472        assert_eq!(b, "def");
473    }
474
475    #[extendr]
476    pub fn vectortypes(a: Vec<i32>, b: Vec<f64>) {
477        assert_eq!(a, [1, 2, 3]);
478        assert_eq!(b, [4., 5., 6.]);
479    }
480
481    #[extendr]
482    pub fn robjtype(a: Robj) {
483        assert_eq!(a, Robj::from(1))
484    }
485
486    #[extendr]
487    pub fn return_u8() -> u8 {
488        123
489    }
490
491    #[extendr]
492    pub fn return_u16() -> u16 {
493        123
494    }
495
496    #[extendr]
497    pub fn return_u32() -> u32 {
498        123
499    }
500
501    #[extendr]
502    pub fn return_u64() -> u64 {
503        123
504    }
505
506    #[extendr]
507    pub fn return_i8() -> i8 {
508        123
509    }
510
511    #[extendr]
512    pub fn return_i16() -> i16 {
513        123
514    }
515
516    #[extendr]
517    pub fn return_i32() -> i32 {
518        123
519    }
520
521    #[extendr]
522    pub fn return_i64() -> i64 {
523        123
524    }
525
526    #[extendr]
527    pub fn return_f32() -> f32 {
528        123.
529    }
530
531    #[extendr]
532    pub fn return_f64() -> f64 {
533        123.
534    }
535
536    #[extendr]
537    pub fn f64_slice(x: &[f64]) -> &[f64] {
538        x
539    }
540
541    #[extendr]
542    pub fn i32_slice(x: &[i32]) -> &[i32] {
543        x
544    }
545
546    #[extendr]
547    pub fn bool_slice(x: &[Bool]) -> &[Bool] {
548        x
549    }
550
551    #[extendr]
552    pub fn f64_iter(x: Real) -> Real {
553        x
554    }
555
556    #[extendr]
557    pub fn i32_iter(x: Int) -> Int {
558        x
559    }
560
561    #[extendr]
562    pub fn bool_iter(x: Logical) -> Logical {
563        x
564    }
565
566    #[extendr]
567    pub fn symbol(x: Symbol) -> Symbol {
568        x
569    }
570
571    #[extendr]
572    pub fn matrix(x: RMatrix<f64>) -> RMatrix<f64> {
573        x
574    }
575
576    #[extendr]
577    pub fn hash_map(x: HashMap<&str, Robj>) -> HashMap<&str, Robj> {
578        x
579    }
580
581    struct Person {
582        pub name: String,
583    }
584
585    #[extendr]
586    /// impl comment.
587    impl Person {
588        fn new() -> Self {
589            Self {
590                name: "".to_string(),
591            }
592        }
593
594        fn set_name(&mut self, name: &str) {
595            self.name = name.to_string();
596        }
597
598        fn name(&self) -> &str {
599            self.name.as_str()
600        }
601    }
602
603    // see metadata_test for the following comments.
604
605    /// comment #1
606    /// comment #2
607    /**
608        comment #3
609        comment #4
610    **/
611    #[extendr]
612    /// aux_func doc comment.
613    fn aux_func(_person: &Person) {}
614
615    // Macro to generate exports
616    extendr_module! {
617        mod my_module;
618        fn aux_func;
619        impl Person;
620    }
621
622    #[test]
623    fn export_test() {
624        test! {
625            use super::*;
626            // Call the exported functions through their generated C wrappers.
627            unsafe {
628                wrap__inttypes(
629                    Robj::from(1).get(),
630                    Robj::from(2).get(),
631                    Robj::from(3).get(),
632                    Robj::from(4).get(),
633                    Robj::from(5).get(),
634                    Robj::from(6).get(),
635                    Robj::from(7).get(),
636                    Robj::from(8).get(),
637                );
638                wrap__inttypes(
639                    Robj::from(1.).get(),
640                    Robj::from(2.).get(),
641                    Robj::from(3.).get(),
642                    Robj::from(4.).get(),
643                    Robj::from(5.).get(),
644                    Robj::from(6.).get(),
645                    Robj::from(7.).get(),
646                    Robj::from(8.).get(),
647                );
648                wrap__floattypes(Robj::from(1.).get(), Robj::from(2.).get());
649                wrap__floattypes(Robj::from(1).get(), Robj::from(2).get());
650                wrap__strtypes(Robj::from("abc").get(), Robj::from("def").get());
651                wrap__vectortypes(
652                    Robj::from(&[1, 2, 3] as &[i32]).get(),
653                    Robj::from(&[4., 5., 6.] as &[f64]).get(),
654                );
655                wrap__robjtype(Robj::from(1).get());
656
657                // General integer types.
658                assert_eq!(new_owned(wrap__return_u8()), Robj::from(123));
659                assert_eq!(new_owned(wrap__return_u16()), Robj::from(123));
660                assert_eq!(new_owned(wrap__return_u32()), Robj::from(123));
661                assert_eq!(new_owned(wrap__return_u64()), Robj::from(123));
662                assert_eq!(new_owned(wrap__return_i8()), Robj::from(123));
663                assert_eq!(new_owned(wrap__return_i16()), Robj::from(123));
664                assert_eq!(new_owned(wrap__return_i32()), Robj::from(123));
665                assert_eq!(new_owned(wrap__return_i64()), Robj::from(123));
666
667                // Floating point types.
668                assert_eq!(new_owned(wrap__return_f32()), Robj::from(123.));
669                assert_eq!(new_owned(wrap__return_f64()), Robj::from(123.));
670            }
671        }
672    }
673
674    #[test]
675    fn class_wrapper_test() {
676        test! {
677            let mut person = Person::new();
678            person.set_name("fred");
679            let robj = r!(person);
680            assert_eq!(robj.check_external_ptr("Person"), true);
681            let person2 = <&Person>::from_robj(&robj).unwrap();
682            assert_eq!(person2.name(), "fred");
683        }
684    }
685
686    #[test]
687    fn slice_test() {
688        test! {
689            unsafe {
690                // #[extendr]
691                // pub fn f64_slice(x: &[f64]) -> &[f64] { x }
692
693                let robj = r!([1., 2., 3.]);
694                assert_eq!(new_owned(wrap__f64_slice(robj.get())), robj);
695
696                // #[extendr]
697                // pub fn i32_slice(x: &[i32]) -> &[i32] { x }
698
699                let robj = r!([1, 2, 3]);
700                assert_eq!(new_owned(wrap__i32_slice(robj.get())), robj);
701
702                // #[extendr]
703                // pub fn bool_slice(x: &[Bool]) -> &[Bool] { x }
704
705                let robj = r!([TRUE, FALSE, TRUE]);
706                assert_eq!(new_owned(wrap__bool_slice(robj.get())), robj);
707
708                // #[extendr]
709                // pub fn f64_iter(x: Real) -> Real { x }
710
711                let robj = r!([1., 2., 3.]);
712                assert_eq!(new_owned(wrap__f64_iter(robj.get())), robj);
713
714                // #[extendr]
715                // pub fn i32_iter(x: Int) -> Int { x }
716
717                let robj = r!([1, 2, 3]);
718                assert_eq!(new_owned(wrap__i32_iter(robj.get())), robj);
719
720                // #[extendr]
721                // pub fn bool_iter(x: Logical) -> Logical { x }
722
723                let robj = r!([TRUE, FALSE, TRUE]);
724                assert_eq!(new_owned(wrap__bool_iter(robj.get())), robj);
725
726                // #[extendr]
727                // pub fn symbol(x: Symbol) -> Symbol { x }
728
729                let robj = sym!(fred);
730                assert_eq!(new_owned(wrap__symbol(robj.get())), robj);
731
732                // #[extendr]
733                // pub fn matrix(x: Matrix<&[f64]>) -> Matrix<&[f64]> { x }
734
735                let m = RMatrix::new_matrix(1, 2, |r, c| if r == c {1.0} else {0.});
736                let robj = r!(m);
737                assert_eq!(new_owned(wrap__matrix(robj.get())), robj);
738
739                // #[extendr]
740                // pub fn hash_map(x: HashMap<&str, Robj>) -> HashMap<&str, Robj> { x }
741                let robj = r!(List::from_values(&[1, 2]));
742                robj.set_attrib(names_symbol(), r!(["a", "b"]))?;
743                let res = new_owned(wrap__hash_map(robj.get()));
744                assert_eq!(res.len(), 2);
745            }
746        }
747    }
748
749    #[test]
750    fn r_output_test() {
751        // R equivalent
752        // > txt_con <- textConnection("test_con", open = "w")
753        // > sink(txt_con)
754        // > cat("Hello world")
755        // > sink()
756        // > close(txt_con)
757        // > expect_equal(test_con, "Hello world")
758        //
759
760        test! {
761            let txt_con = R!(textConnection("test_con", open = "w")).unwrap();
762            call!("sink", &txt_con).unwrap();
763            rprintln!("Hello world");
764            call!("sink").unwrap();
765            call!("close", &txt_con).unwrap();
766            let result = R!(test_con).unwrap();
767            assert_eq!(result, r!("Hello world"));
768        }
769    }
770
771    #[test]
772    fn test_na_str() {
773        assert!(na_str().as_ptr() != "NA".as_ptr());
774        assert_eq!(na_str(), "NA");
775        assert_eq!("NA".is_na(), false);
776        assert_eq!(na_str().is_na(), true);
777    }
778
779    #[test]
780    fn metadata_test() {
781        test! {
782            // Rust interface.
783            let metadata = get_my_module_metadata();
784            assert_eq!(metadata.functions[0].doc, " comment #1\n comment #2\n\n        comment #3\n        comment #4\n    *\n aux_func doc comment.");
785            assert_eq!(metadata.functions[0].name, "aux_func");
786            assert_eq!(metadata.functions[0].args[0].name, "_person");
787            assert_eq!(metadata.functions[1].name, "get_my_module_metadata");
788            assert_eq!(metadata.impls[0].name, "Person");
789            assert_eq!(metadata.impls[0].methods.len(), 3);
790
791            // R interface
792            let robj = unsafe { new_owned(wrap__get_my_module_metadata()) };
793            let functions = robj.dollar("functions").unwrap();
794            let impls = robj.dollar("impls").unwrap();
795            assert_eq!(functions.len(), 3);
796            assert_eq!(impls.len(), 1);
797        }
798    }
799
800    #[test]
801    fn pairlist_macro_works() {
802        test! {
803            assert_eq!(pairlist!(1, 2, 3), Pairlist::from_pairs(&[("", 1), ("", 2), ("", 3)]));
804            assert_eq!(pairlist!(a=1, 2, 3), Pairlist::from_pairs(&[("a", 1), ("", 2), ("", 3)]));
805            assert_eq!(pairlist!(1, b=2, 3), Pairlist::from_pairs(&[("", 1), ("b", 2), ("", 3)]));
806            assert_eq!(pairlist!(a=1, b=2, c=3), Pairlist::from_pairs(&[("a", 1), ("b", 2), ("c", 3)]));
807            assert_eq!(pairlist!(a=NULL), Pairlist::from_pairs(&[("a", ())]));
808            assert_eq!(pairlist!(), Pairlist::from(()));
809        }
810    }
811
812    #[test]
813    fn big_r_macro_works() {
814        test! {
815            assert_eq!(R!("1")?, r!(1.0));
816            assert_eq!(R!(r"1")?, r!(1.0));
817            assert_eq!(R!(r"
818                x <- 1
819                x
820            ")?, r!(1.0));
821            assert_eq!(R!(r"
822                x <- {{ 1.0 }}
823                x
824            ")?, r!(1.0));
825            assert_eq!(R!(r"
826                x <- {{ (0..4).collect_robj() }}
827                x
828            ")?, r!([0, 1, 2, 3]));
829            assert_eq!(R!(r#"
830                x <- "hello"
831                x
832            "#)?, r!("hello"));
833            assert_eq!(Rraw!(r"
834                x <- {{ 1 }}
835                x
836            ")?, r!(1.0));
837        }
838    }
839}