-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a5e4720
commit 27a15eb
Showing
16 changed files
with
1,396 additions
and
1,379 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,78 +1,78 @@ | ||
use crate::TokenStream; | ||
|
||
/// Simplifies the creation of FFI functions | ||
/// | ||
/// # Example | ||
/// ```rust,ignore,no_run | ||
/// #[macros::ffi(type = "system")] | ||
/// pub fn Java_Main_greet<'a>( | ||
/// mut env: JNIEnv<'a>, _class: JClass<'a>, input: JString<'a> | ||
/// ) -> jstring { | ||
/// // First, we have to get the string out of Java. Check out the `strings` | ||
/// // module for more info on how this works. | ||
/// let input: String = env.get_string(&input).expect("Couldn't get java string!").into(); | ||
/// | ||
/// // Then we have to create a new Java string to return. Again, more info | ||
/// // in the `strings` module. | ||
/// let output = env.new_string( | ||
/// format!("Hello, {}!", input) | ||
/// ).expect("Couldn't create java string!"); | ||
/// | ||
/// // Finally, extract the raw pointer to return. | ||
/// output.into_raw() | ||
/// } | ||
/// ``` | ||
pub fn ffi<T: Into<TokenStream>>(cfg: T, input: T) -> TokenStream { | ||
let res = parse_func(input.into()).to_string(); | ||
let settings = parse_settings(cfg.into()); | ||
let res = res.replace("__FFI_RAW_MODIFIERS__", &settings.0); | ||
let res = res.replace("__FFI_EXTERN_MODIFIER__", &settings.1); | ||
match syn::parse_str::<TokenStream>(&res) { | ||
Ok(res) => res, | ||
Err(err) => err.to_compile_error(), | ||
} | ||
} | ||
|
||
/// parses the function it should be attached to | ||
fn parse_func(item: TokenStream) -> TokenStream { | ||
let input = match syn::parse2::<syn::ItemFn>(item) { | ||
Ok(input) => input, | ||
Err(err) => { | ||
return err.to_compile_error(); | ||
} | ||
}; | ||
let ret = &input.sig.output; | ||
let inputs = &input.sig.inputs; | ||
let name = &input.sig.ident; | ||
let generics = &input.sig.generics; | ||
let body = &input.block; | ||
let attrs = &input.attrs; | ||
let vis = &input.vis; | ||
let result = quote::quote! { | ||
#(#attrs)* | ||
#[no_mangle] | ||
#vis __FFI_RAW_MODIFIERS__ extern __FFI_EXTERN_MODIFIER__ fn #name #generics(#inputs) #ret { | ||
#body | ||
} | ||
}; | ||
result | ||
} | ||
|
||
/// parses the settings (can be none, const, unsafe or both) | ||
fn parse_settings(attr: TokenStream) -> (String, String) { | ||
let modifiers_str = attr.to_string(); | ||
let mut res = String::new(); | ||
if modifiers_str.contains("const") { | ||
res.push_str("const "); | ||
} | ||
if modifiers_str.contains("unsafe") { | ||
res.push_str("unsafe "); | ||
} | ||
let t = if modifiers_str.contains("type=") { | ||
let type_str = modifiers_str.split("type=").collect::<Vec<&str>>()[1]; | ||
type_str.split(' ').collect::<Vec<&str>>()[0] | ||
} else { | ||
"C" | ||
}; | ||
(res, format!("\"{}\"",t)) | ||
} | ||
use crate::TokenStream; | ||
|
||
/// Simplifies the creation of FFI functions | ||
/// | ||
/// # Example | ||
/// ```rust,ignore,no_run | ||
/// #[macros::ffi(type = "system")] | ||
/// pub fn Java_Main_greet<'a>( | ||
/// mut env: JNIEnv<'a>, _class: JClass<'a>, input: JString<'a> | ||
/// ) -> jstring { | ||
/// // First, we have to get the string out of Java. Check out the `strings` | ||
/// // module for more info on how this works. | ||
/// let input: String = env.get_string(&input).expect("Couldn't get java string!").into(); | ||
/// | ||
/// // Then we have to create a new Java string to return. Again, more info | ||
/// // in the `strings` module. | ||
/// let output = env.new_string( | ||
/// format!("Hello, {}!", input) | ||
/// ).expect("Couldn't create java string!"); | ||
/// | ||
/// // Finally, extract the raw pointer to return. | ||
/// output.into_raw() | ||
/// } | ||
/// ``` | ||
pub fn ffi<T: Into<TokenStream>>(cfg: T, input: T) -> TokenStream { | ||
let res = parse_func(input.into()).to_string(); | ||
let settings = parse_settings(cfg.into()); | ||
let res = res.replace("__FFI_RAW_MODIFIERS__", &settings.0); | ||
let res = res.replace("__FFI_EXTERN_MODIFIER__", &settings.1); | ||
match syn::parse_str::<TokenStream>(&res) { | ||
Ok(res) => res, | ||
Err(err) => err.to_compile_error(), | ||
} | ||
} | ||
|
||
/// parses the function it should be attached to | ||
fn parse_func(item: TokenStream) -> TokenStream { | ||
let input = match syn::parse2::<syn::ItemFn>(item) { | ||
Ok(input) => input, | ||
Err(err) => { | ||
return err.to_compile_error(); | ||
} | ||
}; | ||
let ret = &input.sig.output; | ||
let inputs = &input.sig.inputs; | ||
let name = &input.sig.ident; | ||
let generics = &input.sig.generics; | ||
let body = &input.block; | ||
let attrs = &input.attrs; | ||
let vis = &input.vis; | ||
let result = quote::quote! { | ||
#(#attrs)* | ||
#[no_mangle] | ||
#vis __FFI_RAW_MODIFIERS__ extern __FFI_EXTERN_MODIFIER__ fn #name #generics(#inputs) #ret { | ||
#body | ||
} | ||
}; | ||
result | ||
} | ||
|
||
/// parses the settings (can be none, const, unsafe or both) | ||
fn parse_settings(attr: TokenStream) -> (String, String) { | ||
let modifiers_str = attr.to_string(); | ||
let mut res = String::new(); | ||
if modifiers_str.contains("const") { | ||
res.push_str("const "); | ||
} | ||
if modifiers_str.contains("unsafe") { | ||
res.push_str("unsafe "); | ||
} | ||
let t = if modifiers_str.contains("type=") { | ||
let type_str = modifiers_str.split("type=").collect::<Vec<&str>>()[1]; | ||
type_str.split(' ').collect::<Vec<&str>>()[0] | ||
} else { | ||
"C" | ||
}; | ||
(res, format!("\"{}\"", t)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,11 @@ | ||
//! A collection of core functionality for the macros. | ||
#![warn(missing_docs, unused, clippy::all)] | ||
|
||
use proc_macro2::TokenStream; | ||
|
||
mod mass_impl; | ||
mod ffi; | ||
|
||
pub use mass_impl::mass_impl; | ||
pub use ffi::ffi; | ||
//! A collection of core functionality for the macros. | ||
#![warn(missing_docs, unused, clippy::all)] | ||
|
||
use proc_macro2::TokenStream; | ||
|
||
mod ffi; | ||
mod mass_impl; | ||
|
||
pub use ffi::ffi; | ||
pub use mass_impl::mass_impl; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,46 @@ | ||
//! Argument parsing for the `mass_impl` macro. | ||
pub use super::variants::TypeVariant; | ||
|
||
/// The configuration for the `mass_impl` macro. | ||
pub struct MassImplMacroConfig { | ||
/// The type variants to implement the trait for. | ||
pub type_variants: Vec<TypeVariant>, | ||
} | ||
|
||
impl std::fmt::Debug for MassImplMacroConfig { | ||
/// Formats a `TypeVariant` | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
f.debug_struct("MassImplMacroConfig") | ||
.field("type_variants", &self.type_variants) | ||
.field("number_of_passthroughs", &self.number_of_passthroughs()) | ||
.finish() | ||
} | ||
} | ||
|
||
impl MassImplMacroConfig { | ||
/// Returns the number of passthroughs for this type variant. | ||
pub fn number_of_passthroughs(&self) -> i32 { | ||
let mut i = 1; | ||
for variant in &self.type_variants { | ||
i *= variant.number_of_passthroughs(); | ||
} | ||
i | ||
} | ||
} | ||
|
||
// parses this: | ||
// $SELF = @R @M Vec2D, | ||
// $OTHER = @R @M Vec2D | ||
// | ||
impl syn::parse::Parse for MassImplMacroConfig { | ||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { | ||
let mut type_variants = Vec::new(); | ||
let vars = syn::punctuated::Punctuated::<TypeVariant, syn::Token![,]>::parse_terminated(input)?; | ||
for var in vars { | ||
type_variants.push(var); | ||
} | ||
Ok(MassImplMacroConfig { | ||
type_variants, | ||
}) | ||
} | ||
} | ||
//! Argument parsing for the `mass_impl` macro. | ||
pub use super::variants::TypeVariant; | ||
|
||
/// The configuration for the `mass_impl` macro. | ||
pub struct MassImplMacroConfig { | ||
/// The type variants to implement the trait for. | ||
pub type_variants: Vec<TypeVariant>, | ||
} | ||
|
||
impl std::fmt::Debug for MassImplMacroConfig { | ||
/// Formats a `TypeVariant` | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
f.debug_struct("MassImplMacroConfig") | ||
.field("type_variants", &self.type_variants) | ||
.field("number_of_passthroughs", &self.number_of_passthroughs()) | ||
.finish() | ||
} | ||
} | ||
|
||
impl MassImplMacroConfig { | ||
/// Returns the number of passthroughs for this type variant. | ||
pub fn number_of_passthroughs(&self) -> i32 { | ||
let mut i = 1; | ||
for variant in &self.type_variants { | ||
i *= variant.number_of_passthroughs(); | ||
} | ||
i | ||
} | ||
} | ||
|
||
// parses this: | ||
// $SELF = @R @M Vec2D, | ||
// $OTHER = @R @M Vec2D | ||
// | ||
impl syn::parse::Parse for MassImplMacroConfig { | ||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { | ||
let mut type_variants = Vec::new(); | ||
let vars = | ||
syn::punctuated::Punctuated::<TypeVariant, syn::Token![,]>::parse_terminated(input)?; | ||
for var in vars { | ||
type_variants.push(var); | ||
} | ||
Ok(MassImplMacroConfig { type_variants }) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,45 @@ | ||
use crate::TokenStream; | ||
|
||
mod variants; | ||
mod args; | ||
|
||
/// A macro for implementing a trait for a list of types. | ||
pub fn mass_impl<T: Into<TokenStream>>(cfg: T, input: T) -> TokenStream { | ||
let cfg: TokenStream = cfg.into(); | ||
let input: TokenStream = input.into(); | ||
let config = match syn::parse2::<args::MassImplMacroConfig>(cfg) { | ||
Ok(config) => config, | ||
Err(err) => { | ||
return err.to_compile_error(); | ||
} | ||
}; | ||
let mut results = vec![input.to_string()]; | ||
|
||
for tv in &config.type_variants { | ||
let mut temp_results = Vec::new(); | ||
if tv.allow_owned { | ||
for r in &results { | ||
let new = r.replace(&tv.alias.to_string(), &tv.ty.to_string()); | ||
temp_results.push(new); | ||
} | ||
} | ||
if tv.allow_ref { | ||
for r in &results { | ||
let new = r.replace(&tv.alias.to_string(), &format!("&{}", tv.ty)); | ||
temp_results.push(new); | ||
} | ||
} | ||
if tv.allow_mut { | ||
for r in &results { | ||
let new = r.replace(&tv.alias.to_string(), &format!("&mut {}", tv.ty)); | ||
temp_results.push(new); | ||
} | ||
} | ||
results = temp_results; | ||
} | ||
let single_str = results.join("\n"); | ||
match syn::parse_str::<TokenStream>(&single_str) { | ||
Ok(ts) => ts, | ||
Err(err) => { | ||
err.to_compile_error() | ||
} | ||
} | ||
} | ||
use crate::TokenStream; | ||
|
||
mod args; | ||
mod variants; | ||
|
||
/// A macro for implementing a trait for a list of types. | ||
pub fn mass_impl<T: Into<TokenStream>>(cfg: T, input: T) -> TokenStream { | ||
let cfg: TokenStream = cfg.into(); | ||
let input: TokenStream = input.into(); | ||
let config = match syn::parse2::<args::MassImplMacroConfig>(cfg) { | ||
Ok(config) => config, | ||
Err(err) => { | ||
return err.to_compile_error(); | ||
} | ||
}; | ||
let mut results = vec![input.to_string()]; | ||
|
||
for tv in &config.type_variants { | ||
let mut temp_results = Vec::new(); | ||
if tv.allow_owned { | ||
for r in &results { | ||
let new = r.replace(&tv.alias.to_string(), &tv.ty.to_string()); | ||
temp_results.push(new); | ||
} | ||
} | ||
if tv.allow_ref { | ||
for r in &results { | ||
let new = r.replace(&tv.alias.to_string(), &format!("&{}", tv.ty)); | ||
temp_results.push(new); | ||
} | ||
} | ||
if tv.allow_mut { | ||
for r in &results { | ||
let new = r.replace(&tv.alias.to_string(), &format!("&mut {}", tv.ty)); | ||
temp_results.push(new); | ||
} | ||
} | ||
results = temp_results; | ||
} | ||
let single_str = results.join("\n"); | ||
match syn::parse_str::<TokenStream>(&single_str) { | ||
Ok(ts) => ts, | ||
Err(err) => err.to_compile_error(), | ||
} | ||
} |
Oops, something went wrong.