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