diff options
Diffstat (limited to 'rola-vcs/internal_macros')
| -rw-r--r-- | rola-vcs/internal_macros/Cargo.toml | 14 | ||||
| -rw-r--r-- | rola-vcs/internal_macros/src/constants.rs | 115 | ||||
| -rw-r--r-- | rola-vcs/internal_macros/src/lib.rs | 39 |
3 files changed, 0 insertions, 168 deletions
diff --git a/rola-vcs/internal_macros/Cargo.toml b/rola-vcs/internal_macros/Cargo.toml deleted file mode 100644 index 0d6f641..0000000 --- a/rola-vcs/internal_macros/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "rorolala_internal_macros" -version.workspace = true -authors.workspace = true -license.workspace = true -edition.workspace = true - -[lib] -proc-macro = true - -[dependencies] -syn = { version = "2", features = ["full"] } -quote = "1" -proc-macro2 = "1" diff --git a/rola-vcs/internal_macros/src/constants.rs b/rola-vcs/internal_macros/src/constants.rs deleted file mode 100644 index 2e76bfe..0000000 --- a/rola-vcs/internal_macros/src/constants.rs +++ /dev/null @@ -1,115 +0,0 @@ -use proc_macro::TokenStream; -use quote::{format_ident, quote}; -use syn::{Expr, Item, ItemConst, ItemMod, Lit, parse_macro_input, parse_quote}; - -/// Entry point called from lib.rs. -pub fn expand(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut input_mod = parse_macro_input!(item as ItemMod); - - let (_, items) = match &mut input_mod.content { - Some(content) => content, - None => panic!("#[constants] can only be applied to a module with a body"), - }; - - let mut new_items: Vec<Item> = Vec::with_capacity(items.len()); - - for item in items.iter() { - if let Item::Const(const_item) = item { - let func = transform_const(const_item); - new_items.push(func); - } else { - new_items.push(item.clone()); - } - } - - let mod_ident = &input_mod.ident; - let vis = &input_mod.vis; - - let output = quote! { - #[allow(non_snake_case)] - #vis mod #mod_ident { - #(#new_items)* - } - }; - - output.into() -} - -/// Transforms a single `const` item into a function. -fn transform_const(const_item: &ItemConst) -> Item { - let name = &const_item.ident; - let attrs = &const_item.attrs; - - // Extract the string literal value from the const - let value_str = match &*const_item.expr { - Expr::Lit(expr_lit) => match &expr_lit.lit { - Lit::Str(lit_str) => lit_str.value(), - _ => panic!( - "#[constants] only supports `&str` literals, \ - but `{name}` has a non-string literal" - ), - }, - _ => panic!( - "#[constants] only supports literal expressions, \ - but `{name}` has a non-literal expression" - ), - }; - - let placeholders = extract_placeholders(&value_str); - - if placeholders.is_empty() { - parse_quote! { - #(#attrs)* - pub fn #name() -> String { - #value_str.to_string() - } - } - } else { - let params: Vec<_> = placeholders - .iter() - .map(|p| { - let ident = format_ident!("{p}"); - quote! { #ident: impl ::core::convert::AsRef<str> } - }) - .collect(); - - let format_args: Vec<_> = placeholders - .iter() - .map(|p| { - let ident = format_ident!("{p}"); - quote! { #ident = #ident.as_ref() } - }) - .collect(); - - parse_quote! { - #(#attrs)* - pub fn #name(#(#params),*) -> String { - ::std::format!(#value_str, #(#format_args),*) - } - } - } -} - -/// Extracts all `{name}` placeholder identifiers from a format string. -fn extract_placeholders(s: &str) -> Vec<String> { - let mut placeholders = Vec::new(); - let mut chars = s.char_indices().peekable(); - - while let Some((_, c)) = chars.next() { - if c == '{' { - let mut name = String::new(); - for (_, c) in &mut chars { - if c == '}' { - break; - } - name.push(c); - } - let trimmed = name.trim().to_string(); - if !trimmed.is_empty() { - placeholders.push(trimmed); - } - } - } - - placeholders -} diff --git a/rola-vcs/internal_macros/src/lib.rs b/rola-vcs/internal_macros/src/lib.rs deleted file mode 100644 index f6c3cb7..0000000 --- a/rola-vcs/internal_macros/src/lib.rs +++ /dev/null @@ -1,39 +0,0 @@ -mod constants; - -use proc_macro::TokenStream; - -/// Transforms `pub const` items in a module into equivalent functions. -/// -/// Constants without `{param}` placeholders become `fn NAME() -> String`. -/// Constants with `{param}` placeholders become `fn NAME(param: impl AsRef<str>) -> String`, -/// using `format!()` to fill in the placeholders. -/// -/// The entire module is annotated with `#[allow(non_snake_case)]`. -/// -/// # Example -/// -/// ```ignore -/// #[rorolala_internal_macros::constants] -/// pub mod paths { -/// pub const ROLA_DRAFT_DIR: &str = ".rola"; -/// pub const ROLA_BINDED_BUCKET_FILE: &str = ".rola/BIND/{bucket}"; -/// } -/// ``` -/// -/// expands to: -/// -/// ```ignore -/// #[allow(non_snake_case)] -/// pub mod paths { -/// pub fn ROLA_DRAFT_DIR() -> String { -/// ".rola".to_string() -/// } -/// pub fn ROLA_BINDED_BUCKET_FILE(bucket: impl AsRef<str>) -> String { -/// format!(".rola/BIND/{bucket}", bucket = bucket.as_ref()) -/// } -/// } -/// ``` -#[proc_macro_attribute] -pub fn constants(attr: TokenStream, item: TokenStream) -> TokenStream { - constants::expand(attr, item) -} |
