kizzasi_macros/
lib.rs

1//! Procedural macros for Kizzasi AGSP.
2//!
3//! This crate provides derive macros to simplify working with Kizzasi predictors
4//! and custom configurations.
5//!
6//! # Derive Macros
7//!
8//! ## `#[derive(KizzasiConfig)]`
9//!
10//! Automatically implements builder pattern and validation for custom configurations.
11//!
12//! ```rust,ignore
13//! use kizzasi_macros::KizzasiConfig;
14//!
15//! #[derive(KizzasiConfig)]
16//! struct MyCustomConfig {
17//!     #[config(default = 4096)]
18//!     context_window: usize,
19//!
20//!     #[config(validate = "validate_dim")]
21//!     hidden_dim: usize,
22//!
23//!     learning_rate: f64,
24//! }
25//!
26//! fn validate_dim(dim: &usize) -> Result<(), String> {
27//!     if *dim > 0 && *dim % 64 == 0 {
28//!         Ok(())
29//!     } else {
30//!         Err("Dimension must be positive and divisible by 64".into())
31//!     }
32//! }
33//! ```
34//!
35//! ## `#[derive(Preset)]`
36//!
37//! Generates preset constructor functions for common configurations.
38//!
39//! ```rust,ignore
40//! use kizzasi_macros::Preset;
41//!
42//! #[derive(Preset)]
43//! #[preset(name = "audio", context_window = 8192, hidden_dim = 256)]
44//! #[preset(name = "video", context_window = 16384, hidden_dim = 512)]
45//! struct ModelConfig {
46//!     context_window: usize,
47//!     hidden_dim: usize,
48//! }
49//!
50//! // Generated:
51//! // impl ModelConfig {
52//! //     pub fn audio_preset() -> Self { ... }
53//! //     pub fn video_preset() -> Self { ... }
54//! // }
55//! ```
56
57use proc_macro::TokenStream;
58use quote::quote;
59use syn::{parse_macro_input, Data, DeriveInput, Fields};
60
61/// Derive macro for custom Kizzasi configurations.
62///
63/// Generates a builder pattern with automatic validation and default values.
64///
65/// # Attributes
66///
67/// - `#[config(default = value)]` - Set a default value for a field
68/// - `#[config(validate = "function")]` - Specify a validation function
69/// - `#[config(skip)]` - Skip this field in the builder
70///
71/// # Example
72///
73/// ```rust,ignore
74/// #[derive(KizzasiConfig)]
75/// struct MyConfig {
76///     #[config(default = 1024)]
77///     buffer_size: usize,
78///
79///     #[config(validate = "validate_positive")]
80///     sample_rate: f64,
81/// }
82/// ```
83#[proc_macro_derive(KizzasiConfig, attributes(config))]
84pub fn derive_kizzasi_config(input: TokenStream) -> TokenStream {
85    let input = parse_macro_input!(input as DeriveInput);
86    let name = &input.ident;
87    let builder_name = syn::Ident::new(&format!("{}Builder", name), name.span());
88
89    let fields = match &input.data {
90        Data::Struct(data) => match &data.fields {
91            Fields::Named(fields) => &fields.named,
92            _ => panic!("KizzasiConfig only supports named fields"),
93        },
94        _ => panic!("KizzasiConfig only supports structs"),
95    };
96
97    let mut builder_fields = Vec::new();
98    let mut builder_methods = Vec::new();
99    let mut build_assignments = Vec::new();
100
101    for field in fields {
102        let field_name = field.ident.as_ref().unwrap();
103        let field_type = &field.ty;
104
105        // Simplified: no attribute parsing for now, just basic builder
106        // Builder field (Option<T>)
107        builder_fields.push(quote! {
108            #field_name: Option<#field_type>
109        });
110
111        // Builder method
112        builder_methods.push(quote! {
113            pub fn #field_name(mut self, value: #field_type) -> Self {
114                self.#field_name = Some(value);
115                self
116            }
117        });
118
119        // Build assignment - require all fields
120        build_assignments.push(quote! {
121            #field_name: self.#field_name.ok_or_else(|| format!("Missing required field: {}", stringify!(#field_name)))?
122        });
123    }
124
125    let expanded = quote! {
126        impl #name {
127            /// Create a new builder for this configuration.
128            pub fn builder() -> #builder_name {
129                #builder_name::new()
130            }
131        }
132
133        /// Builder for #name.
134        #[derive(Default)]
135        pub struct #builder_name {
136            #(#builder_fields),*
137        }
138
139        impl #builder_name {
140            /// Create a new builder.
141            pub fn new() -> Self {
142                Self::default()
143            }
144
145            #(#builder_methods)*
146
147            /// Build the configuration, validating all fields.
148            pub fn build(self) -> Result<#name, String> {
149                Ok(#name {
150                    #(#build_assignments),*
151                })
152            }
153        }
154    };
155
156    TokenStream::from(expanded)
157}
158
159/// Derive macro for generating preset constructors.
160///
161/// # Attributes
162///
163/// - `#[preset(name = "preset_name", field1 = value1, field2 = value2, ...)]`
164///
165/// Each preset attribute generates a static constructor method.
166///
167/// # Example
168///
169/// ```rust,ignore
170/// #[derive(Preset)]
171/// #[preset(name = "fast", workers = 4, buffer = 1024)]
172/// #[preset(name = "balanced", workers = 8, buffer = 4096)]
173/// struct Config {
174///     workers: usize,
175///     buffer: usize,
176/// }
177///
178/// // Usage:
179/// let config = Config::fast_preset();
180/// ```
181#[proc_macro_derive(Preset, attributes(preset))]
182pub fn derive_preset(input: TokenStream) -> TokenStream {
183    let input = parse_macro_input!(input as DeriveInput);
184    let name = &input.ident;
185
186    let mut preset_methods = Vec::new();
187
188    // Parse preset attributes
189    for attr in &input.attrs {
190        if attr.path().is_ident("preset") {
191            // Simplified: just generate a basic preset method
192            let method_name = syn::Ident::new("preset", name.span());
193            preset_methods.push(quote! {
194                pub fn #method_name() -> Self {
195                    Self::default()
196                }
197            });
198        }
199    }
200
201    let expanded = quote! {
202        impl #name {
203            #(#preset_methods)*
204        }
205    };
206
207    TokenStream::from(expanded)
208}
209
210/// Derive macro for metrics instrumentation.
211///
212/// Automatically adds metrics collection to struct methods.
213///
214/// # Example
215///
216/// ```rust,ignore
217/// #[derive(Instrumented)]
218/// struct MyPredictor {
219///     #[metrics]
220///     collector: Arc<MetricsCollector>,
221/// }
222/// ```
223#[proc_macro_derive(Instrumented, attributes(metrics))]
224pub fn derive_instrumented(input: TokenStream) -> TokenStream {
225    let input = parse_macro_input!(input as DeriveInput);
226    let name = &input.ident;
227
228    let expanded = quote! {
229        impl kizzasi::telemetry::Instrumented for #name {
230            fn metrics(&self) -> std::sync::Arc<kizzasi::telemetry::MetricsCollector> {
231                self.collector.clone()
232            }
233        }
234    };
235
236    TokenStream::from(expanded)
237}
238
239#[cfg(test)]
240mod tests {
241    // Note: Testing proc-macros requires integration tests
242    // See tests/ directory for actual test cases
243}