extendr_macros/
extendr_options.rs

1use syn::{meta::ParseNestedMeta, Lit, LitBool};
2
3#[derive(Debug, Default)]
4pub(crate) struct ExtendrOptions {
5    /// Name of the corresponding R object
6    pub r_name: Option<String>,
7    /// `mod_name` is the name of the exported C symbol for `#[extendr]`-`fn`,
8    /// and a post-fix on exported methods for `#[extendr]`-`impl`.
9    pub mod_name: Option<String>,
10    /// Flag ensuring that R's Random Number Generator state is acquired and returned to
11    /// R. See [WRE, Section 6.3 number generation](https://cran.r-project.org/doc/manuals/R-exts.html#Random-numbers)
12    pub use_rng: bool,
13    pub invisible: Option<bool>,
14}
15
16impl ExtendrOptions {
17    /// Parse a set of attribute arguments for `#[extendr(opts...)]`
18    ///
19    /// Supported options:
20    ///
21    /// - `r_name = "name"` which specifies the name of the wrapper on the R-side.
22    /// - `use_rng = bool` ensures the RNG-state is pulled and pushed
23    ///
24    pub fn parse(&mut self, meta: ParseNestedMeta) -> syn::parse::Result<()> {
25        let path = meta
26            .path
27            .get_ident()
28            .ok_or(meta.error("Unexpected syntax"))?;
29
30        match path.to_string().as_str() {
31            "invisible" => {
32                self.invisible = Some(true);
33                Ok(())
34            }
35            _ => {
36                let value = meta.value()?;
37                match path.to_string().as_str() {
38                    "r_name" => {
39                        if let Ok(Lit::Str(litstr)) = value.parse() {
40                            self.r_name = Some(litstr.value());
41                            Ok(())
42                        } else {
43                            Err(value.error("`r_name` must be a string literal"))
44                        }
45                    }
46                    "mod_name" => {
47                        if let Ok(Lit::Str(litstr)) = value.parse() {
48                            self.mod_name = Some(litstr.value());
49                            Ok(())
50                        } else {
51                            Err(value.error("`mod_name` must be a string literal"))
52                        }
53                    }
54                    "use_rng" => {
55                        if let Ok(LitBool { value, .. }) = value.parse() {
56                            self.use_rng = value;
57                            Ok(())
58                        } else {
59                            Err(value.error("`use_rng` must be `true` or `false`"))
60                        }
61                    }
62                    _ => Err(syn::Error::new_spanned(meta.path, "Unexpected key")),
63                }
64            }
65        }
66    }
67}