simple_agents_macros/lib.rs
1//! Procedural macros for SimpleAgents.
2//!
3//! This crate provides derive macros for automatic schema generation and partial type
4//! support for streaming responses.
5//!
6//! # Macros
7//!
8//! - [`PartialType`] - Generates a partial version of a type with all fields as `Option<T>`
9//!
10//! # Example
11//!
12//! ```rust
13//! use simple_agents_macros::PartialType;
14//! use serde::{Deserialize, Serialize};
15//!
16//! #[derive(Debug, Clone, PartialType, Serialize, Deserialize)]
17//! pub struct User {
18//! pub id: u64,
19//! pub name: String,
20//! pub email: String,
21//! pub age: u32,
22//! }
23//!
24//! let partial = PartialUser {
25//! id: Some(1),
26//! name: Some("Ada".to_string()),
27//! email: Some("ada@example.com".to_string()),
28//! age: Some(42),
29//! };
30//! let user = User::from_partial(partial).unwrap();
31//! assert_eq!(user.name, "Ada");
32//! ```
33
34#![deny(missing_docs)]
35
36mod partial;
37
38use proc_macro::TokenStream;
39
40/// Derives a partial type for streaming support.
41///
42/// Generates a `Partial{TypeName}` struct with all fields wrapped in `Option<T>`.
43/// The partial type is useful for progressive emission during streaming responses,
44/// where not all fields may be available yet.
45///
46/// # Generated Code
47///
48/// For each struct annotated with `#[derive(PartialType)]`, this macro generates:
49///
50/// 1. **Partial Struct**: `Partial{TypeName}` with all fields as `Option<T>`
51/// - Derives: `Debug`, `Clone`, `Default`, `Serialize`, `Deserialize`
52///
53/// 2. **Conversion Method**: `from_partial()` on the original type
54/// - Converts `PartialType` → `Type`
55/// - Returns `Result<Type, String>` (error if required fields missing)
56///
57/// 3. **Merge Method**: `merge()` on the partial type
58/// - Merges two partial values (newer values take precedence)
59///
60/// # Field Attributes
61///
62/// - `#[partial(skip)]` - Exclude field from partial type (always uses default)
63/// - `#[partial(default)]` - Use default value if missing in partial
64///
65/// # Example
66///
67/// ```rust
68/// use simple_agents_macros::PartialType;
69/// use std::time::Duration;
70///
71/// #[derive(PartialType)]
72/// pub struct Resume {
73/// pub name: String,
74/// pub email: String,
75/// #[partial(default)]
76/// pub skills: Vec<String>,
77/// #[partial(skip)]
78/// pub created_at: Duration,
79/// }
80///
81/// let mut partial = PartialResume::default();
82/// partial.name = Some("Alice".to_string());
83/// assert_eq!(partial.email, None);
84///
85/// partial.merge(PartialResume {
86/// email: Some("alice@example.com".to_string()),
87/// skills: Some(vec!["Rust".to_string()]),
88/// ..Default::default()
89/// });
90///
91/// let resume = Resume::from_partial(partial).unwrap();
92/// assert_eq!(resume.name, "Alice");
93/// assert_eq!(resume.skills, vec!["Rust".to_string()]);
94/// ```
95///
96/// # Streaming Annotations
97///
98/// Future versions will support streaming annotations:
99/// - `#[partial(stream_not_null)]` - Don't emit until non-null
100/// - `#[partial(stream_done)]` - Only emit when complete
101#[proc_macro_derive(PartialType, attributes(partial))]
102pub fn derive_partial_type(input: TokenStream) -> TokenStream {
103 partial::derive(input)
104}