type_state_builder/
lib.rs

1//! Type-State Builder Pattern Implementation
2//!
3//! A derive macro that generates compile-time safe builders using the type-state pattern.
4//! It prevents incomplete object construction by making missing required fields a
5//! compile-time error rather than a runtime failure.
6//!
7//! For complete documentation, installation instructions, and guides, see the
8//! [README](https://github.com/welf/type-state-builder#readme).
9//!
10//! # Design Philosophy
11//!
12//! This crate was designed with AI-assisted development in mind. Two principles
13//! guided its design:
14//!
15//! ## Compiler-Enforced Correctness
16//!
17//! In AI-assisted development, code generation happens rapidly. By encoding field
18//! requirements in the type system, errors are caught immediately by the compiler
19//! rather than manifesting as runtime failures. If the code compiles, the builder
20//! is correctly configured.
21//!
22//! ## Actionable Error Messages
23//!
24//! Instead of using generic type parameters to track field states (which produce
25//! cryptic error messages), this crate generates named structs for each state:
26//!
27//! ```text
28//! UserBuilder_HasName_MissingEmail    // Name set, email missing
29//! UserBuilder_HasName_HasEmail        // Both set - build() available
30//! ```
31//!
32//! When an error occurs, the type name immediately indicates which fields are missing.
33//! This is particularly valuable for AI assistants that can parse and act on the error.
34//!
35//! ## Trade-offs
36//!
37//! This approach generates more structs than type-parameter-based solutions, slightly
38//! increasing compile time. However, the improved error message clarity is worth this
39//! cost. There is no runtime cost due to Rust's zero-cost abstractions.
40//!
41//! # Compatibility
42//!
43//! - **no_std**: Fully compatible. Generated code uses only `core` types.
44//! - **MSRV**: Rust 1.70.0 or later.
45//!
46//! # Overview
47//!
48//! The macro automatically selects between two builder patterns:
49//!
50//! - **Type-State Builder**: For structs with required fields, providing compile-time
51//!   safety that prevents calling `build()` until all required fields are set
52//! - **Regular Builder**: For structs with only optional fields, providing a simple
53//!   builder with immediate `build()` availability
54//!
55//! # Quick Start
56//!
57//! Add the derive macro to your struct and mark required fields:
58//!
59//! ```
60//! use type_state_builder::TypeStateBuilder;
61//!
62//! #[derive(TypeStateBuilder)]
63//! #[builder(impl_into)]   // Setters arguments are now `impl Into<FieldType>`
64//! struct User {
65//!     #[builder(required)]
66//!     name: String,
67//!
68//!     #[builder(required)]
69//!     email: String,
70//!
71//!     #[builder(default = Some(30))] // Default value for age
72//!     age: Option<u32>,
73//!
74//!     #[builder(setter_prefix = "is_")] // The setter is now named `is_active`
75//!     active: bool, // Will use Default::default() if not set
76//! }
77//!
78//! // Usage - this enforces that name and email are set
79//! let user = User::builder()
80//!     .name("Alice")              // `impl_into` allows to pass any type that can be converted into String
81//!     .email("alice@example.com") // `impl_into` allows to pass any type that can be converted into String
82//!     // age is not set and defaults to Some(30)
83//!     // active is not set and defaults to false (Default::default())
84//!     .build(); // The `build()` method is available since all required fields are set
85
86//!
87//! assert_eq!(user.name, "Alice".to_string());
88//! assert_eq!(user.email, "alice@example.com".to_string());
89//! assert_eq!(user.age, Some(30));
90//! assert_eq!(user.active, false);
91//! ```
92//!
93//! # Supported Attributes
94//!
95//! ## Struct-level Attributes
96//!
97//! - `#[builder(build_method = "method_name")]` - Custom build method name
98//! - `#[builder(setter_prefix = "prefix_")]` - Prefix for all setter method names
99//! - `#[builder(impl_into)]` - Generate setters with `impl Into<FieldType>` parameters
100//!
101//! ## Field-level Attributes
102//!
103//! - `#[builder(required)]` - Mark field as required
104//! - `#[builder(setter_name = "name")]` - Custom setter method name
105//! - `#[builder(setter_prefix = "prefix_")]` - Custom prefix for setter method name
106//! - `#[builder(default = expression)]` - Custom default value
107//! - `#[builder(skip_setter)]` - Don't generate setter (requires default)
108//! - `#[builder(impl_into)]` - Generate setter with `impl Into<FieldType>` parameter
109//! - `#[builder(impl_into = false)]` - Override struct-level `impl_into` for this field
110//! - `#[builder(converter = |param: InputType| -> FieldType { expression })` - Custom conversion logic for setter input
111//!
112//! # Advanced Examples
113//!
114//! ## Custom Defaults and Setter Names
115//!
116//! ```
117//! use type_state_builder::TypeStateBuilder;
118//!
119//! #[derive(TypeStateBuilder)]
120//! #[builder(build_method = "create")]
121//! struct Document {
122//!     #[builder(required)]
123//!     title: String,
124//!
125//!     #[builder(required, setter_name = "set_content")]
126//!     content: String,
127//!
128//!     #[builder(default = 42)]
129//!     page_count: u32,
130//!
131//!     #[builder(default = String::from("draft"), skip_setter)]
132//!     status: String,
133//! }
134//!
135//! let doc = Document::builder()
136//!     .title("My Document".to_string())
137//!     .set_content("Document content here".to_string())
138//!     .create(); // Custom build method name
139//! ```
140//!
141//! ## Generic Types and Lifetimes
142//!
143//! ```
144//! use type_state_builder::TypeStateBuilder;
145//!
146//! #[derive(TypeStateBuilder)]
147//! struct Container<T: Clone>
148//! where
149//!     T: Send
150//! {
151//!     #[builder(required)]
152//!     value: T,
153//!
154//!     #[builder(required)]
155//!     name: String,
156//!
157//!     tags: Vec<String>,
158//! }
159//!
160//! let container = Container::builder()
161//!     .value(42)
162//!     .name("test".to_string())
163//!     .tags(vec!["tag1".to_string()])
164//!     .build();
165//! ```
166//!
167//! ## Setter Prefix Examples
168//!
169//! ```
170//! use type_state_builder::TypeStateBuilder;
171//!
172//! // Struct-level setter prefix applies to all fields
173//! #[derive(TypeStateBuilder)]
174//! #[builder(setter_prefix = "with_")]
175//! struct Config {
176//!     #[builder(required)]
177//!     host: String,
178//!
179//!     #[builder(required)]
180//!     port: u16,
181//!
182//!     timeout: Option<u32>,
183//! }
184//!
185//! let config = Config::builder()
186//!     .with_host("localhost".to_string())
187//!     .with_port(8080)
188//!     .with_timeout(Some(30))
189//!     .build();
190//! ```
191//!
192//! ```
193//! use type_state_builder::TypeStateBuilder;
194//!
195//! // Field-level setter prefix overrides struct-level prefix
196//! #[derive(TypeStateBuilder)]
197//! #[builder(setter_prefix = "with_")]
198//! struct Database {
199//!     #[builder(required)]
200//!     connection_string: String,
201//!
202//!     #[builder(required, setter_prefix = "set_")]
203//!     credentials: String,
204//!
205//!     #[builder(setter_name = "timeout_seconds")]
206//!     timeout: Option<u32>,
207//! }
208//!
209//! let db = Database::builder()
210//!     .with_connection_string("postgresql://...".to_string())
211//!     .set_credentials("user:pass".to_string())
212//!     .with_timeout_seconds(Some(60))
213//!     .build();
214//! ```
215//!
216//! ## Ergonomic Conversions with `impl_into`
217//!
218//! The `impl_into` attribute generates setter methods that accept `impl Into<FieldType>`
219//! parameters, allowing for more ergonomic API usage by automatically converting
220//! compatible types.
221//!
222//! ```
223//! use type_state_builder::TypeStateBuilder;
224//!
225//! // Struct-level impl_into applies to all setters
226//! #[derive(TypeStateBuilder)]
227//! #[builder(impl_into)]
228//! struct ApiClient {
229//!     #[builder(required)]
230//!     base_url: String,
231//!
232//!     #[builder(required)]
233//!     api_key: String,
234//!
235//!     timeout: Option<u32>,
236//!     user_agent: String, // Uses Default::default()
237//! }
238//!
239//! // Can now use &str directly instead of String::from() or .to_string()
240//! let client = ApiClient::builder()
241//!     .base_url("https://api.example.com")    // &str -> String
242//!     .api_key("secret-key")                   // &str -> String
243//!     .timeout(Some(30))
244//!     .user_agent("MyApp/1.0")                 // &str -> String
245//!     .build();
246//! ```
247//!
248//! ```
249//! use type_state_builder::TypeStateBuilder;
250//!
251//! // Field-level control with precedence rules
252//! #[derive(TypeStateBuilder)]
253//! #[builder(impl_into)]  // Default for all fields
254//! struct Document {
255//!     #[builder(required)]
256//!     title: String,  // Inherits impl_into = true
257//!
258//!     #[builder(required, impl_into = false)]
259//!     content: String,  // Override: requires String directly
260//!
261//!     #[builder(impl_into = true)]
262//!     category: Option<String>,  // Explicit impl_into = true
263//!
264//!     #[builder(impl_into = false)]
265//!     tags: Vec<String>,  // Override: requires Vec<String> directly
266//! }
267//!
268//! let doc = Document::builder()
269//!     .title("My Document")                // &str -> String (inherited)
270//!     .content("Content".to_string())      // Must use String (override)
271//!     .category(Some("tech".to_string()))  // impl Into for Option<String>
272//!     .tags(vec!["rust".to_string()])      // Must use Vec<String> (override)
273//!     .build();
274//! ```
275//!
276//! **Note**: `impl_into` is incompatible with `skip_setter` since skipped fields
277//! don't have setter methods generated.
278//!
279//! ### Complete `impl_into` Example
280//!
281//! ```
282//! use type_state_builder::TypeStateBuilder;
283//! use std::path::PathBuf;
284//!
285//! // Demonstrate both struct-level and field-level impl_into usage
286//! #[derive(TypeStateBuilder)]
287//! #[builder(impl_into)]  // Struct-level default: enable for all fields
288//! struct CompleteExample {
289//!     #[builder(required)]
290//!     name: String,                        // Inherits: accepts impl Into<String>
291//!
292//!     #[builder(required, impl_into = false)]
293//!     id: String,                          // Override: requires String directly
294//!
295//!     #[builder(impl_into = true)]
296//!     description: Option<String>,         // Explicit: accepts impl Into<String>
297//!
298//!     #[builder(default = PathBuf::from("/tmp"))]
299//!     work_dir: PathBuf,                   // Inherits: accepts impl Into<PathBuf>
300//!
301//!     #[builder(impl_into = false, default = Vec::new())]
302//!     tags: Vec<String>,                   // Override: requires Vec<String>
303//! }
304//!
305//! // Usage demonstrating the different setter behaviors
306//! let example = CompleteExample::builder()
307//!     .name("Alice")                       // &str -> String (inherited impl_into)
308//!     .id("user_123".to_string())          // Must use String (override = false)
309//!     .description(Some("Engineer".to_string()))  // Option<String> required
310//!     .work_dir("/home/alice")             // &str -> PathBuf (inherited impl_into)
311//!     .tags(vec!["rust".to_string()])      // Must use Vec<String> (override = false)
312//!     .build();
313//!
314//! assert_eq!(example.name, "Alice");
315//! assert_eq!(example.id, "user_123");
316//! assert_eq!(example.description, Some("Engineer".to_string()));
317//! assert_eq!(example.work_dir, PathBuf::from("/home/alice"));
318//! assert_eq!(example.tags, vec!["rust"]);
319//! ```
320//!
321//! ## Custom Conversions with `converter`
322//!
323//! The `converter` attribute allows you to specify custom conversion logic for field setters,
324//! enabling more powerful transformations than `impl_into` can provide. Use closure syntax
325//! to define the conversion function with explicit parameter types.
326//!
327//! ```
328//! use type_state_builder::TypeStateBuilder;
329//!
330//! #[derive(TypeStateBuilder)]
331//! struct User {
332//!     #[builder(required)]
333//!     name: String,
334//!
335//!     // Normalize email to lowercase and trim whitespace
336//!     #[builder(required, converter = |email: &str| email.trim().to_lowercase())]
337//!     email: String,
338//!
339//!     // Parse comma-separated tags into Vec<String>
340//!     #[builder(converter = |tags: &str| tags.split(',').map(|s| s.trim().to_string()).collect())]
341//!     interests: Vec<String>,
342//!
343//!     // Parse age from string with fallback
344//!     #[builder(converter = |age: &str| age.parse().unwrap_or(0))]
345//!     age: u32,
346//! }
347//!
348//! let user = User::builder()
349//!     .name("Alice".to_string())
350//!     .email("  ALICE@EXAMPLE.COM  ")  // Will be normalized to "alice@example.com"
351//!     .interests("rust, programming, web")  // Parsed to Vec<String>
352//!     .age("25")  // Parsed from string to u32
353//!     .build();
354//!
355//! assert_eq!(user.email, "alice@example.com");
356//! assert_eq!(user.interests, vec!["rust", "programming", "web"]);
357//! assert_eq!(user.age, 25);
358//! ```
359//!
360//! ### Complex Converter Examples
361//!
362//! ```
363//! use type_state_builder::TypeStateBuilder;
364//! use std::collections::HashMap;
365//!
366//! #[derive(TypeStateBuilder)]
367//! struct Config {
368//!     // Convert environment-style boolean strings
369//!     #[builder(converter = |enabled: &str| {
370//!         matches!(enabled.to_lowercase().as_str(), "true" | "1" | "yes" | "on")
371//!     })]
372//!     debug_enabled: bool,
373//!
374//!     // Parse key=value pairs into HashMap
375//!     #[builder(converter = |pairs: &str| {
376//!         pairs.split(',')
377//!              .filter_map(|pair| {
378//!                  let mut split = pair.split('=');
379//!                  Some((split.next()?.trim().to_string(),
380//!                       split.next()?.trim().to_string()))
381//!              })
382//!              .collect()
383//!     })]
384//!     env_vars: HashMap<String, String>,
385//!
386//!     // Transform slice to owned Vec
387//!     #[builder(converter = |hosts: &[&str]| {
388//!         hosts.iter().map(|s| s.to_string()).collect()
389//!     })]
390//!     allowed_hosts: Vec<String>,
391//! }
392//!
393//! let config = Config::builder()
394//!     .debug_enabled("true")
395//!     .env_vars("LOG_LEVEL=debug,PORT=8080")
396//!     .allowed_hosts(&["localhost", "127.0.0.1"])
397//!     .build();
398//!
399//! assert_eq!(config.debug_enabled, true);
400//! assert_eq!(config.env_vars.get("LOG_LEVEL"), Some(&"debug".to_string()));
401//! assert_eq!(config.allowed_hosts, vec!["localhost", "127.0.0.1"]);
402//! ```
403//!
404//! ### Converter with Generics
405//!
406//! ```
407//! use type_state_builder::TypeStateBuilder;
408//!
409//! #[derive(TypeStateBuilder)]
410//! struct Container<T: Clone + Default> {
411//!     #[builder(required, impl_into)]
412//!     name: String,
413//!
414//!     // Converter works with generic fields too
415//!     #[builder(converter = |items: &[T]| items.into_iter().map(|item| item.clone()).collect())]
416//!     data: Vec<T>,
417//! }
418//!
419//! // Usage with concrete type
420//! let container = Container::builder()
421//!     .name("numbers")        // Convert &str to String thanks to `impl_into`
422//!     .data(&[1, 2, 3, 4, 5]) // Convert &[T] to Vec<T> thanks to `converter`
423//!     .build();               // Available only when all required fields are set
424//!
425//! assert_eq!(container.data, vec![1, 2, 3, 4, 5]);
426//! ```
427//!
428//! ### Converter vs impl_into Comparison
429//!
430//! | Feature | `impl_into` | `converter` |
431//! |---------|-------------|-------------|
432//! | **Type conversions** | Only `Into` trait | Any custom logic |
433//! | **Parsing strings** | Limited | Full support |
434//! | **Data validation** | No | Custom validation |
435//! | **Complex transformations** | No | Full support |
436//! | **Multiple input formats** | Into only | Any input type |
437//! | **Performance** | Zero-cost | Depends on logic |
438//! | **Syntax** | Attribute flag | Closure expression |
439//!
440//! **When to use `converter`:**
441//! - Ergonomic setter generation for `Option<String>` fields
442//! - Parsing structured data from strings
443//! - Normalizing or validating input data
444//! - Complex data transformations
445//! - Converting between incompatible types
446//! - Custom business logic in setters
447//!
448//! **Note**: `converter` is incompatible with `skip_setter` and `impl_into` since
449//! they represent different approaches to setter generation.
450//!
451//! ## Optional-Only Structs (Regular Builder)
452//!
453//! ```
454//! use type_state_builder::TypeStateBuilder;
455//!
456//! // No required fields = regular builder pattern
457//! #[derive(TypeStateBuilder)]
458//! struct Settings {
459//!     debug: bool,
460//!     max_connections: Option<u32>,
461//!
462//!     #[builder(default = "default.log".to_string())]
463//!     log_file: String,
464//!
465//!     #[builder(skip_setter, default = 42)]
466//!     magic_number: i32,
467//! }
468//!
469//! // Can call build() immediately since no required fields
470//! let settings = Settings::builder()
471//!     .debug(true)
472//!     .max_connections(Some(100))
473//!     .build();
474//! ```
475//!
476//! # Error Prevention
477//!
478//! The macro prevents common mistakes at compile time:
479//!
480//! ```compile_fail
481//! use type_state_builder::TypeStateBuilder;
482//!
483//! #[derive(TypeStateBuilder)]
484//! struct User {
485//!     #[builder(required)]
486//!     name: String,
487//! }
488//!
489//! let user = User::builder().build(); // ERROR: required field not set
490//! ```
491//!
492//! ```compile_fail
493//! use type_state_builder::TypeStateBuilder;
494//!
495//! #[derive(TypeStateBuilder)]
496//! struct BadConfig {
497//!     #[builder(required, default = test)]  // ERROR: Invalid combination
498//!     name: String,
499//! }
500//! ```
501//!
502//! # Invalid Attribute Combinations
503//!
504//! Several attribute combinations are invalid and will produce compile-time errors
505//! with helpful error messages:
506//!
507//! ## skip_setter + setter_name
508//!
509//! You can't name a setter method that doesn't exist:
510//!
511//! ```compile_fail
512//! use type_state_builder::TypeStateBuilder;
513//!
514//! #[derive(TypeStateBuilder)]
515//! struct InvalidSetterName {
516//!     #[builder(skip_setter, setter_name = "custom_name")]  // ERROR: Conflicting attributes
517//!     field: String,
518//! }
519//! ```
520//!
521//! ## skip_setter + setter_prefix
522//!
523//! You can't apply prefixes to non-existent setter methods:
524//!
525//! ```compile_fail
526//! use type_state_builder::TypeStateBuilder;
527//!
528//! #[derive(TypeStateBuilder)]
529//! struct InvalidSetterPrefix {
530//!     #[builder(skip_setter, setter_prefix = "with_")]  // ERROR: Conflicting attributes
531//!     field: String,
532//! }
533//! ```
534//!
535//! ## skip_setter + impl_into
536//!
537//! Skipped setters can't have parameter conversion rules:
538//!
539//! ```compile_fail
540//! use type_state_builder::TypeStateBuilder;
541//!
542//! #[derive(TypeStateBuilder)]
543//! struct InvalidImplInto {
544//!     #[builder(skip_setter, impl_into = true)]  // ERROR: Conflicting attributes
545//!     field: String,
546//! }
547//! ```
548//!
549//! ## skip_setter + converter
550//!
551//! Skipped setters can't have custom conversion logic:
552//!
553//! ```compile_fail
554//! use type_state_builder::TypeStateBuilder;
555//!
556//! #[derive(TypeStateBuilder)]
557//! struct InvalidConverter {
558//!     #[builder(skip_setter, converter = |x: String| x)]  // ERROR: Conflicting attributes
559//!     field: String,
560//! }
561//! ```
562//!
563//! ## converter + impl_into
564//!
565//! Custom converters and `impl_into` are different approaches to parameter handling:
566//!
567//! ```compile_fail
568//! use type_state_builder::TypeStateBuilder;
569//!
570//! #[derive(TypeStateBuilder)]
571//! struct InvalidConverterImplInto {
572//!     #[builder(converter = |x: String| x, impl_into = true)]  // ERROR: Conflicting attributes
573//!     field: String,
574//! }
575//! ```
576//!
577//! ## skip_setter + required
578//!
579//! Required fields must have setter methods:
580//!
581//! ```compile_fail
582//! use type_state_builder::TypeStateBuilder;
583//!
584//! #[derive(TypeStateBuilder)]
585//! struct InvalidRequired {
586//!     #[builder(skip_setter, required)]  // ERROR: Conflicting attributes
587//!     field: String,
588//! }
589//! ```
590//!
591//! # Module Organization
592//!
593//! The crate is organized into several modules that handle different aspects
594//! of the builder generation process. Most users will only interact with the
595//! [`TypeStateBuilder`] derive macro.
596//!
597//! For complete documentation, examples, and guides, see the
598//! [README](https://github.com/welf/type-state-builder#readme).
599
600use proc_macro::TokenStream;
601use syn::{parse_macro_input, DeriveInput};
602
603// Internal modules - not exported due to proc-macro restrictions
604mod analysis;
605mod attributes;
606mod generation;
607mod utils;
608mod validation;
609
610/// Derives a type-safe builder for a struct with compile-time validation of required fields.
611///
612/// This macro automatically generates an appropriate builder pattern based on the struct
613/// configuration:
614/// - **Type-State Builder** for structs with required fields
615/// - **Regular Builder** for structs with only optional fields
616///
617/// # Basic Usage
618///
619/// ```
620/// use type_state_builder::TypeStateBuilder;
621///
622/// #[derive(TypeStateBuilder)]
623/// struct Person {
624///     #[builder(required)]
625///     name: String,
626///     age: Option<u32>,
627/// }
628///
629/// let person = Person::builder()
630///     .name("Alice".to_string())
631///     .build();
632/// ```
633///
634/// # Attribute Reference
635///
636/// ## Struct Attributes
637///
638/// - `#[builder(build_method = "name")]` - Custom build method name (default: "build")
639/// - `#[builder(setter_prefix = "prefix_")]` - Prefix for all setter method names
640///
641/// ## Field Attributes
642///
643/// - `#[builder(required)]` - Field must be set before build() (creates type-state builder)
644/// - `#[builder(setter_name = "name")]` - Custom setter method name
645/// - `#[builder(setter_prefix = "prefix_")]` - Custom prefix for this field's setter (overrides struct-level)
646/// - `#[builder(default = expr)]` - Custom default value (must be valid Rust expression)
647/// - `#[builder(skip_setter)]` - Don't generate setter method (requires default value)
648///
649/// # Generated Methods
650///
651/// The macro generates:
652/// - `YourStruct::builder()` - Creates a new builder instance
653/// - `.field_name(value)` - Setter methods for each field (unless skipped)
654/// - `.build()` - Constructs the final instance (or custom name from `build_method`)
655///
656/// # Compile-Time Safety
657///
658/// The type-state builder (used when there are required fields) prevents:
659/// - Calling `build()` before setting required fields
660/// - Setting the same required field multiple times
661/// - Invalid attribute combinations
662///
663/// # Error Messages
664///
665/// The macro provides clear error messages for common mistakes:
666/// - Missing required fields at build time
667/// - Invalid attribute combinations
668/// - Generic parameter mismatches
669/// - Syntax errors in default values
670///
671/// # Examples
672///
673/// ```
674/// use type_state_builder::TypeStateBuilder;
675///
676/// #[derive(TypeStateBuilder)]
677/// struct User {
678///     #[builder(required)]
679///     name: String,
680///     age: Option<u32>,
681/// }
682///
683/// let user = User::builder()
684///     .name("Alice".to_string())
685///     .build();
686/// ```
687#[proc_macro_derive(TypeStateBuilder, attributes(builder))]
688pub fn derive_type_state_builder(input: TokenStream) -> TokenStream {
689    let input = parse_macro_input!(input as DeriveInput);
690
691    match generate_builder_implementation(&input) {
692        Ok(tokens) => tokens.into(),
693        Err(error) => error.to_compile_error().into(),
694    }
695}
696
697/// Generates the complete builder implementation for a struct.
698///
699/// This is the main implementation function that coordinates the analysis,
700/// validation, and generation process.
701///
702/// # Arguments
703///
704/// * `input` - The parsed derive input from the struct definition
705///
706/// # Returns
707///
708/// A `syn::Result<proc_macro2::TokenStream>` containing the complete builder
709/// implementation or detailed error information.
710///
711/// # Process
712///
713/// 1. **Analysis** - Parse and analyze the struct definition
714/// 2. **Validation** - Ensure the configuration is valid
715/// 3. **Generation** - Create the appropriate builder code
716/// 4. **Assembly** - Combine all components into the final output
717///
718/// # Error Handling
719///
720/// Errors are returned with detailed information about:
721/// - What went wrong during analysis or generation
722/// - How to fix configuration issues
723/// - Examples of correct usage
724fn generate_builder_implementation(input: &DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
725    // Step 1: Analyze the struct definition
726    let analysis = analysis::analyze_struct(input)?;
727
728    // Step 2: Validate the analysis for builder generation
729    analysis.validate_for_generation()?;
730
731    // Step 3: Generate the appropriate builder implementation
732    generation::generate_builder(&analysis)
733}
734
735// Internal types for testing - not exported due to proc-macro restrictions
736
737#[cfg(test)]
738mod tests {
739    use super::*;
740    use syn::parse_quote;
741
742    #[test]
743    fn test_derive_macro_with_required_fields() {
744        let input: DeriveInput = parse_quote! {
745            struct Example {
746                #[builder(required)]
747                name: String,
748                age: Option<u32>,
749            }
750        };
751
752        let result = generate_builder_implementation(&input);
753        assert!(result.is_ok());
754
755        let tokens = result.unwrap();
756        let code = tokens.to_string();
757
758        // Should contain builder method
759        assert!(code.contains("builder"));
760        // Should contain setter for required field
761        assert!(code.contains("name"));
762        // Should contain build method
763        assert!(code.contains("build"));
764    }
765
766    #[test]
767    fn test_derive_macro_with_optional_only() {
768        let input: DeriveInput = parse_quote! {
769            struct Example {
770                name: Option<String>,
771                age: u32,
772            }
773        };
774
775        let result = generate_builder_implementation(&input);
776        assert!(result.is_ok());
777
778        let tokens = result.unwrap();
779        let code = tokens.to_string();
780
781        // Should generate regular builder for optional-only struct
782        assert!(code.contains("builder"));
783        assert!(code.contains("build"));
784    }
785
786    #[test]
787    fn test_derive_macro_with_custom_attributes() {
788        let input: DeriveInput = parse_quote! {
789            #[builder(build_method = "create")]
790            struct Example {
791                #[builder(required, setter_name = "set_name")]
792                name: String,
793
794                #[builder(default = 42)]
795                count: i32,
796            }
797        };
798
799        let result = generate_builder_implementation(&input);
800        assert!(result.is_ok());
801
802        let tokens = result.unwrap();
803        let code = tokens.to_string();
804
805        // Should respect custom build method name
806        assert!(code.contains("create"));
807        // Should respect custom setter name
808        assert!(code.contains("set_name"));
809    }
810
811    #[test]
812    fn test_derive_macro_with_generics() {
813        let input: DeriveInput = parse_quote! {
814            struct Example<T: Clone> {
815                #[builder(required)]
816                value: T,
817                name: String,
818            }
819        };
820
821        let result = generate_builder_implementation(&input);
822        assert!(result.is_ok());
823
824        let tokens = result.unwrap();
825        let code = tokens.to_string();
826
827        // Should handle generics properly
828        assert!(code.contains("<"));
829        assert!(code.contains("T"));
830    }
831
832    #[test]
833    fn test_derive_macro_with_undeclared_generic() {
834        // This test verifies that undeclared generics are allowed through our validation
835        // and the Rust compiler will catch the error later
836        let input: DeriveInput = parse_quote! {
837            struct Example {
838                value: T,  // T is not declared - Rust compiler will catch this
839            }
840        };
841
842        let result = generate_builder_implementation(&input);
843        // Should succeed in our validation (Rust compiler will catch undeclared generic later)
844        assert!(result.is_ok());
845
846        let code = result.unwrap().to_string();
847        // Should generate code that includes the undeclared generic
848        assert!(code.contains("value"));
849    }
850
851    #[test]
852    fn test_unsupported_input_types() {
853        // Test enum - should fail
854        let enum_input: DeriveInput = parse_quote! {
855            enum Example {
856                A, B
857            }
858        };
859        let result = generate_builder_implementation(&enum_input);
860        assert!(result.is_err());
861
862        // Test tuple struct - should fail
863        let tuple_input: DeriveInput = parse_quote! {
864            struct Example(String, i32);
865        };
866        let result = generate_builder_implementation(&tuple_input);
867        assert!(result.is_err());
868
869        // Test unit struct - should fail
870        let unit_input: DeriveInput = parse_quote! {
871            struct Example;
872        };
873        let result = generate_builder_implementation(&unit_input);
874        assert!(result.is_err());
875    }
876}