Skip to content

Commit

Permalink
extendr-macro: moved ExtendrOptions around as it was scattered..
Browse files Browse the repository at this point in the history
  • Loading branch information
CGMossa committed Feb 18, 2024
1 parent 5bd58e1 commit b400d39
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 85 deletions.
17 changes: 11 additions & 6 deletions extendr-macros/src/extendr_enum.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
use quote::{format_ident, quote};

use crate::extendr_options::ExtendrOptions;

//TODO: Variants with Named structs, that happens to be ExternalPtr<NamedStruct>
// could be supported. The API needs investigation though..

/// Adds the ability to take an `enum` of plain variants and turn them into
/// an R factor.
///
/// an R factor.
///
/// The order of the enums listed in Rust dictates the order in `levels`.
/// We do not use the discriminant value (if specified) for anything.
///
///
pub(crate) fn extendr_enum(item_enum: syn::ItemEnum) -> proc_macro::TokenStream {
///
///
pub(crate) fn extendr_enum(
item_enum: syn::ItemEnum,
opts: &ExtendrOptions,
) -> proc_macro::TokenStream {
//TODO: error on opts that isn't used here:
// first, inherent &opts, and see if any value is provided..

//FIXME: sanitize field names, as sometimes they have r# etc.
let enum_name = &item_enum.ident;

Expand Down
59 changes: 3 additions & 56 deletions extendr-macros/src/extendr_function.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::wrappers;
use crate::{extendr_options::ExtendrOptions, wrappers};
use proc_macro::TokenStream;
use quote::quote;
use syn::{meta::ParseNestedMeta, ItemFn, Lit, LitBool};
use syn::ItemFn;

/// Generate bindings for a single function.
pub fn extendr_function(mut func: ItemFn, opts: &wrappers::ExtendrOptions) -> TokenStream {
pub fn extendr_function(mut func: ItemFn, opts: &ExtendrOptions) -> TokenStream {
let mut wrappers: Vec<ItemFn> = Vec::new();
wrappers::make_function_wrappers(opts, &mut wrappers, "", &func.attrs, &mut func.sig, None);

Expand All @@ -14,56 +14,3 @@ pub fn extendr_function(mut func: ItemFn, opts: &wrappers::ExtendrOptions) -> To
# ( #wrappers )*
})
}

impl wrappers::ExtendrOptions {
/// Parse a set of attribute arguments for `#[extendr(opts...)]`
///
/// Supported options:
///
/// - `use_try_from = bool` which uses `TryFrom<Robj>` for argument conversions.
/// - `r_name = "name"` which specifies the name of the wrapper on the R-side.
/// - `use_rng = bool` ensures the RNG-state is pulled and pushed
///
pub fn parse(&mut self, meta: ParseNestedMeta) -> syn::parse::Result<()> {
fn help_message() -> ! {
panic!("expected #[extendr(use_try_from = bool, r_name = \"name\", mod_name = \"r_mod_name\", use_rng = bool)]");
}

let value = match meta.value() {
Ok(value) => value,
Err(_) => help_message(),
};

if meta.path.is_ident("use_try_from") {
if let Ok(LitBool { value, .. }) = value.parse() {
self.use_try_from = value;
Ok(())
} else {
help_message();
}
} else if meta.path.is_ident("r_name") {
if let Ok(Lit::Str(litstr)) = value.parse() {
self.r_name = Some(litstr.value());
Ok(())
} else {
help_message();
}
} else if meta.path.is_ident("mod_name") {
if let Ok(Lit::Str(litstr)) = value.parse() {
self.mod_name = Some(litstr.value());
Ok(())
} else {
help_message();
}
} else if meta.path.is_ident("use_rng") {
if let Ok(LitBool { value, .. }) = value.parse() {
self.use_rng = value;
Ok(())
} else {
help_message();
}
} else {
help_message();
}
}
}
17 changes: 5 additions & 12 deletions extendr-macros/src/extendr_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use proc_macro::TokenStream;
use quote::{format_ident, quote};
use syn::{ItemFn, ItemImpl};

use crate::wrappers;
use crate::{extendr_options::ExtendrOptions, wrappers};

/// Handle trait implementations.
///
Expand Down Expand Up @@ -36,7 +36,7 @@ use crate::wrappers;
/// fn aux_func;
/// }
/// ```
pub fn extendr_impl(mut item_impl: ItemImpl) -> TokenStream {
pub fn extendr_impl(mut item_impl: ItemImpl, opts: &ExtendrOptions) -> TokenStream {
// Only `impl name { }` allowed
if item_impl.defaultness.is_some() {
return quote! { compile_error!("default not allowed in #[extendr] impl"); }.into();
Expand All @@ -62,7 +62,7 @@ pub fn extendr_impl(mut item_impl: ItemImpl) -> TokenStream {
return quote! { compile_error!("where clause not allowed in #[extendr] impl"); }.into();
}

let opts = wrappers::ExtendrOptions::default();
let opts = ExtendrOptions::default();
let self_ty = item_impl.self_ty.as_ref();
let self_ty_name = wrappers::type_name(self_ty);
let prefix = format!("{}__", self_ty_name);
Expand Down Expand Up @@ -103,6 +103,8 @@ pub fn extendr_impl(mut item_impl: ItemImpl) -> TokenStream {

let meta_name = format_ident!("{}{self_ty_name}", wrappers::META_PREFIX);

//FIXME: use `opts` and `use_try_from` here!

let expanded = TokenStream::from(quote! {
// The impl itself copied from the source.
#item_impl
Expand Down Expand Up @@ -136,15 +138,6 @@ pub fn extendr_impl(mut item_impl: ItemImpl) -> TokenStream {
}
}

//FIXME: where is this used?
// impl extendr_api::IntoRobj for #self_ty {
// fn into_robj(self) -> Robj {
// let res = ExternalPtr::new(self).into();
// res.set_attrib(class_symbol(), #self_ty_name).unwrap();
// res
// }
// }

// Output conversion function for this type.
impl From<#self_ty> for Robj {
fn from(value: #self_ty) -> Self {
Expand Down
65 changes: 65 additions & 0 deletions extendr-macros/src/extendr_options.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use syn::{meta::ParseNestedMeta, Lit, LitBool};

#[derive(Debug, Default)]
pub struct ExtendrOptions {
pub use_try_from: bool,
pub r_name: Option<String>,
pub mod_name: Option<String>,
pub use_rng: bool,
/// For `#[extendr]` on `enum`s, there is a wrapper around `Vec<EnumType>`
/// generated; Default to `VecEnumtype`.
pub vec_name: Option<String>,
}

impl ExtendrOptions {
/// Parse a set of attribute arguments for `#[extendr(opts...)]`
///
/// Supported options:
///
/// - `use_try_from = bool` which uses `TryFrom<Robj>` for argument conversions.
/// - `r_name = "name"` which specifies the name of the wrapper on the R-side.
/// - `use_rng = bool` ensures the RNG-state is pulled and pushed
///
pub fn parse(&mut self, meta: ParseNestedMeta) -> syn::parse::Result<()> {
fn help_message() -> ! {
panic!("expected #[extendr(use_try_from = bool, r_name = \"name\", mod_name = \"r_mod_name\", use_rng = bool)]");
}

let value = match meta.value() {
Ok(value) => value,
Err(_) => help_message(),
};

if meta.path.is_ident("use_try_from") {
if let Ok(LitBool { value, .. }) = value.parse() {
self.use_try_from = value;
Ok(())
} else {
help_message();
}
} else if meta.path.is_ident("r_name") {
if let Ok(Lit::Str(litstr)) = value.parse() {
self.r_name = Some(litstr.value());
Ok(())
} else {
help_message();
}
} else if meta.path.is_ident("mod_name") {
if let Ok(Lit::Str(litstr)) = value.parse() {
self.mod_name = Some(litstr.value());
Ok(())
} else {
help_message();
}
} else if meta.path.is_ident("use_rng") {
if let Ok(LitBool { value, .. }) = value.parse() {
self.use_rng = value;
Ok(())
} else {
help_message();
}
} else {
help_message();
}
}
}
8 changes: 6 additions & 2 deletions extendr-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,13 @@
mod R;
mod call;
mod dataframe;
// region: #[extendr] macro
mod extendr_enum;
mod extendr_function;
mod extendr_impl;
mod extendr_module;
mod extendr_enum;
mod extendr_options;
// endregion
mod list;
mod list_struct;
mod pairlist;
Expand All @@ -74,7 +77,8 @@ use syn::{parse_macro_input, Item};

#[proc_macro_attribute]
pub fn extendr(attr: TokenStream, item: TokenStream) -> TokenStream {
let mut opts = wrappers::ExtendrOptions::default();
let item = parse_macro_input!(item as Item);
let mut opts = extendr_options::ExtendrOptions::default();

let extendr_opts_parser = syn::meta::parser(|meta| opts.parse(meta));
parse_macro_input!(attr with extendr_opts_parser);
Expand Down
12 changes: 3 additions & 9 deletions extendr-macros/src/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,11 @@ use proc_macro2::Ident;
use quote::{format_ident, quote};
use syn::{parse_quote, punctuated::Punctuated, Expr, ExprLit, FnArg, ItemFn, Token, Type};

use crate::extendr_options::ExtendrOptions;

pub const META_PREFIX: &str = "meta__";
pub const WRAP_PREFIX: &str = "wrap__";

#[derive(Debug, Default)]
pub struct ExtendrOptions {
pub use_try_from: bool,
pub r_name: Option<String>,
pub mod_name: Option<String>,
pub use_rng: bool,
}

// Generate wrappers for a specific function.
pub fn make_function_wrappers(
opts: &ExtendrOptions,
Expand Down Expand Up @@ -150,7 +144,7 @@ pub fn make_function_wrappers(
},
}
};

let return_type_conversion = if !return_is_ref_self {
if opts.use_try_from {
quote!(Ok(#call_name(#actual_args).try_into()?))
Expand Down

0 comments on commit b400d39

Please sign in to comment.