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