diff options
Diffstat (limited to 'pish_derive/src')
| -rw-r--r-- | pish_derive/src/lib.rs | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/pish_derive/src/lib.rs b/pish_derive/src/lib.rs index 3a296fc..3a2fddc 100644 --- a/pish_derive/src/lib.rs +++ b/pish_derive/src/lib.rs @@ -94,3 +94,67 @@ pub fn derive_cli(input: TokenStream) -> TokenStream { TokenStream::from(expanded) } + +// AI-generated +#[proc_macro_derive(Variants)] +pub fn derive_variants(item: TokenStream) -> TokenStream { + let original = item.to_string(); + + // ---- extract enum name ---- + let mut tokens = original.split_whitespace(); + + let mut enum_name = None; + while let Some(t) = tokens.next() { + if t == "enum" { + enum_name = tokens.next().map(|s| s.trim_matches('{').to_string()); + break; + } + } + + let enum_name = match enum_name { + Some(n) => n, + None => return r#"compile_error!("expected enum")"#.parse().unwrap(), + }; + + // ---- extract body between braces ---- + let start = original.find('{').expect("missing '{'"); + let end = original.rfind('}').expect("missing '}'"); + let body = &original[start + 1..end]; + + // ---- parse variants ---- + let mut variants = Vec::new(); + + for part in body.split(',') { + let v = part.trim(); + if v.is_empty() { + continue; + } + + // take first token as variant name + let name = v.split_whitespace().next().unwrap_or("").trim(); + + if name.is_empty() { + continue; + } + + // reject non-unit variants + if v.contains('(') || v.contains('{') || v.contains('=') { + return r#"compile_error!("only unit variants supported")"#.parse().unwrap(); + } + + variants.push(format!("{}::{}", enum_name, name)); + } + + let variants_joined = variants.join(", "); + + let expanded = format!( + " +impl crate::variants::Variants for {enum_name} {{ + const VARIANTS: &'static [Self] = &[ + {variants_joined} + ]; +}}" + ); + + expanded.parse().unwrap() +} |
