aboutsummaryrefslogtreecommitdiffstats
path: root/pish_derive
diff options
context:
space:
mode:
Diffstat (limited to 'pish_derive')
-rw-r--r--pish_derive/src/lib.rs64
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()
+}