entid_derive/lib.rs
1/* Copyright © 2025, CosmicMind, Inc. */
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{parse_macro_input, DeriveInput, Expr, Lit};
6
7/// Attribute for setting the prefix for an entity
8#[proc_macro_attribute]
9pub fn prefix(_attr: TokenStream, item: TokenStream) -> TokenStream {
10 // This is just a marker attribute, so we return the item unchanged
11 item
12}
13
14/// Attribute for setting the delimiter for an entity
15#[proc_macro_attribute]
16pub fn delimiter(_attr: TokenStream, item: TokenStream) -> TokenStream {
17 // This is just a marker attribute, so we return the item unchanged
18 item
19}
20
21/// Derive macro for implementing the `Prefix` trait
22///
23/// # Attributes
24///
25/// - `#[entid(prefix = "...")]` - Sets the prefix for the entity (required)
26/// - `#[entid(delimiter = "...")]` - Sets the delimiter for the entity (optional, defaults to "_")
27///
28/// # Example
29///
30/// ```rust
31/// use entid::Prefix;
32///
33/// #[derive(Prefix)]
34/// #[entid(prefix = "user", delimiter = "_")]
35/// struct User;
36///
37/// #[derive(Prefix)]
38/// #[entid(prefix = "post", delimiter = "-")]
39/// struct Post;
40///
41/// // The delimiter is optional and defaults to "_"
42/// #[derive(Prefix)]
43/// #[entid(prefix = "comment")]
44/// struct Comment;
45/// ```
46#[proc_macro_derive(Prefix, attributes(entid))]
47pub fn derive_prefix(input: TokenStream) -> TokenStream {
48 let input = parse_macro_input!(input as DeriveInput);
49 let name = &input.ident;
50
51 // Default values
52 let mut prefix = format!("{}_", name).to_lowercase();
53 let mut delimiter = String::from("_");
54
55 // Parse attributes
56 for attr in &input.attrs {
57 if attr.path().is_ident("entid") {
58 attr.parse_nested_meta(|meta| {
59 if meta.path.is_ident("prefix") {
60 let value = meta.value()?;
61 let expr: Expr = value.parse()?;
62 if let Expr::Lit(expr_lit) = expr {
63 if let Lit::Str(lit_str) = expr_lit.lit {
64 prefix = lit_str.value();
65 }
66 }
67 } else if meta.path.is_ident("delimiter") {
68 let value = meta.value()?;
69 let expr: Expr = value.parse()?;
70 if let Expr::Lit(expr_lit) = expr {
71 if let Lit::Str(lit_str) = expr_lit.lit {
72 delimiter = lit_str.value();
73 }
74 }
75 }
76 Ok(())
77 })
78 .ok();
79 }
80 }
81
82 let gen = quote! {
83 impl entid::Prefix for #name {
84 fn prefix() -> &'static str {
85 #prefix
86 }
87
88 fn delimiter() -> &'static str {
89 #delimiter
90 }
91 }
92 };
93
94 gen.into()
95}