Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bisync/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ repository = "https://github.com/JM4ier/bisync"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bisync_macros = "0.2.3"
bisync_macros = { path = "../bisync_macros" }
8 changes: 5 additions & 3 deletions bisync/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,13 @@ pub mod asynchronous {
pub use ::bisync_macros::internal_delete as only_sync;
/// Specialize an item to only be emitted in the asynchronous module
pub use ::bisync_macros::internal_noop as only_async;
/// Emit an item in both synchronous and asynchronous code, and adjust asynchronisity depending on location
pub use ::bisync_macros::internal_noop as bisync;
/// Emit an item in both synchronous and asynchronous code.
/// If an `async_suffix = "some_suffix"` attribute is provided *to this macro*,
/// it transforms `method().await` to `method_some_suffix().await`.
/// Otherwise (no `async_suffix` or empty `async_suffix`), it acts like a no-op for the async code structure.
pub use ::bisync_macros::internal_transform_async as bisync;
/// true in the synchronous module, otherwise false
pub const SYNC: bool = false;
/// true in the asynchronous module, otherwise false
pub const ASYNC: bool = true;
}

3 changes: 3 additions & 0 deletions bisync_macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ repository = "https://github.com/JM4ier/bisync"
proc-macro = true

[dependencies]
syn = { version = "2.0", features = ["full", "visit-mut"] }
quote = "1.0"
proc-macro2 = "1.0"
44 changes: 44 additions & 0 deletions bisync_macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Do not use this crate directly.

use proc_macro::{Group, TokenStream};
use quote::quote;
use syn::{parse_macro_input, visit_mut::VisitMut, Expr, ItemFn};

#[proc_macro_attribute]
pub fn internal_noop(_attr: TokenStream, item: TokenStream) -> TokenStream {
Expand Down Expand Up @@ -55,3 +57,45 @@ pub fn internal_strip_async(attr: TokenStream, item: TokenStream) -> TokenStream

new.into_iter().collect()
}

struct MethodTransformer {
suffix: String,
}

impl VisitMut for MethodTransformer {
fn visit_expr_mut(&mut self, expr: &mut Expr) {
if let Expr::Await(await_expr) = expr {
if let Expr::MethodCall(method_call) = &mut *await_expr.base {
let new_method_name = format!("{}_{}", method_call.method, self.suffix);
method_call.method = syn::Ident::new(&new_method_name, method_call.method.span());
}
}
syn::visit_mut::visit_expr_mut(self, expr);
}
}

#[proc_macro_attribute]
pub fn internal_transform_async(attr: TokenStream, item: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(item as ItemFn);
let attr_str = attr.to_string();
let suffix = if attr_str.contains("async_suffix") {
let parts: Vec<&str> = attr_str.split('=').map(|s| s.trim()).collect();
if parts.len() == 2 {
parts[1].trim_matches('"').to_string()
} else {
"".to_string()
}
} else {
"".to_string()
};

if !suffix.is_empty() {
let mut transformer = MethodTransformer { suffix };
transformer.visit_item_fn_mut(&mut input);
}

let output = quote! {
#input
};
output.into()
}