Expand description
§Former - Advanced Builder Pattern Implementation
The Former crate provides a comprehensive derive macro ecosystem for implementing the Builder Pattern in Rust with advanced features like subform support, custom validation, and flexible configuration.
§Core Features
- Fluent Builder API: Generate clean, ergonomic builder interfaces
- Advanced Generic Support: Handle complex generic parameters and lifetime constraints
- Subform Integration: Build nested structures with full type safety
- Collection Builders: Specialized support for Vec, HashMap, HashSet, and custom collections
- Custom Validation: Pre-formation validation through custom mutators
- Flexible Configuration: Extensive attribute system for fine-grained control
- No-std Compatibility: Full support for no-std environments with optional alloc
§Quick Start
use former::Former;
#[derive(Debug, PartialEq, Former)]
pub struct UserProfile {
age: i32,
username: String,
bio_optional: Option<String>,
}
let profile = UserProfile::former()
.age(30)
.username("JohnDoe".to_string())
.bio_optional("Software Developer".to_string())
.form();
§Architecture Overview
The Former pattern generates several key components:
- Storage Struct: Holds intermediate state during building (all fields are
Option<T>
) - Former Struct: The main builder providing the fluent API
- Definition Types: Type system integration for advanced scenarios
- Trait Implementations: Integration with the broader Former ecosystem
§Debug Support
The Former derive macro provides comprehensive debugging capabilities through the #[debug]
attribute,
following the design principle that “Proc Macros: Must Implement a ‘debug’ Attribute”.
§Using Debug Attribute
use former::Former;
// Standalone debug attribute
#[derive(Debug, PartialEq, Former)]
// #[debug] // <-- Commented out - debug attribute only for temporary debugging
pub struct Person {
name: String,
age: u32,
email: Option<String>,
}
// Within #[former(...)] container
#[derive(Debug, PartialEq, Former)]
// #[former(debug, standalone_constructors)] // <-- Debug commented out
pub struct Config {
host: String,
port: u16,
}
§Debug Output Categories
When #[debug]
is present and the former_diagnostics_print_generated
feature is enabled,
the macro provides detailed information in four phases:
- Input Analysis: Target type, generic parameters, fields/variants, attribute configuration
- Generic Classification: How generics are categorized and processed
- Generated Components: Complete breakdown of Former ecosystem components
- Final Generated Code: The complete TokenStream output
§Enabling Debug Output
# See debug information during compilation
cargo build --features former_diagnostics_print_generated
# For examples
cargo run --example former_debug --features former_diagnostics_print_generated
§Debug Benefits
- Understand Macro Behavior: See exactly how the macro processes your struct/enum
- Debug Complex Scenarios: Troubleshoot generic parameters, lifetimes, trait bounds
- Learn Former Pattern: Understand the complete generated ecosystem
- Verify Configuration: Confirm attribute parsing and code generation decisions
§Integration Points
This crate serves as the main entry point and integrates:
former_meta
: Procedural macro implementationformer_types
: Core traits and type definitions- External collections through [
collection_tools
]
For detailed examples and advanced usage patterns, see the module documentation and the comprehensive examples in the repository.
§Module :: former
A flexible implementation of the Builder pattern supporting nested builders, collection-specific subformers, and comprehensive enum variant constructors.
§What is Former
?
The former
crate provides a powerful derive macro, #[ derive( Former ) ]
, that automatically implements the Builder pattern for your Rust structs and enums.
Its primary goal is to simplify the construction of complex objects, especially those with numerous fields, optional values, default settings, collections, nested structures, or complex enum variants, making your initialization code more readable and maintainable.
For enums, former
automatically generates constructors for each variant, intelligently choosing between direct constructors, subformers, and standalone functions based on the variant structure and applied attributes.
§Why Use Former
?
Compared to manually implementing the Builder pattern or using other builder crates, former
offers several advantages:
- Reduced Boilerplate:
#[ derive( Former ) ]
automatically generates the builder struct, storage, and setters, saving you significant repetitive coding effort. - Fluent & Readable API: Construct objects step-by-step using clear, chainable methods (
.field_name( value )
). - Intelligent Enum Support: Automatically generates appropriate constructors for enum variants:
- Unit variants get direct constructors (e.g.,
Status::active()
) - Simple variants get scalar constructors (e.g.,
Message::text("hello")
) - Complex variants get subformers for step-by-step construction
- Flexible attributes (
#[scalar]
,#[subform_scalar]
,#[standalone_constructors]
) for fine-grained control
- Unit variants get direct constructors (e.g.,
- Effortless Defaults & Optionals: Fields automatically use their
Default
implementation if not set.Option< T >
fields are handled seamlessly – you only set them if you have aSome( value )
. Custom defaults can be specified easily with#[ former( default = ... ) ]
. - Powerful Collection & Nested Struct Handling:
former
truly shines with its subformer system. Easily buildVec
,HashMap
,HashSet
, and other collections element-by-element, or configure nested structs using their own dedicated formers within the parent’s builder chain. This is often more complex to achieve with other solutions.
§Installation
Add former
to your Cargo.toml
:
cargo add former
The default features enable the Former
derive macro and support for standard collections, covering most common use cases.
§Basic Usage
Derive Former
on your struct and use the generated ::former()
method to start building:
use former::Former;
#[ derive( Debug, PartialEq, Former ) ]
pub struct UserProfile
{
age : i32, // Required field
username : String, // Required field
bio : Option< String >, // Optional field
}
let profile = UserProfile::former()
.age( 30 )
.username( "JohnDoe".to_string() )
// .bio is optional, so we don't *have* to call its setter
.form();
let expected = UserProfile
{
age : 30,
username : "JohnDoe".to_string(),
bio : None, // Defaults to None if not set
};
assert_eq!( profile, expected );
dbg!( &profile );
// > &profile = UserProfile {
// > age: 30,
// > username: "JohnDoe",
// > bio: None,
// > }
// Example setting the optional field:
let profile_with_bio = UserProfile::former()
.age( 30 )
.username( "JohnDoe".to_string() )
.bio( "Software Developer".to_string() ) // Set the optional bio
.form();
let expected_with_bio = UserProfile
{
age : 30,
username : "JohnDoe".to_string(),
bio : Some( "Software Developer".to_string() ),
};
assert_eq!( profile_with_bio, expected_with_bio );
dbg!( &profile_with_bio );
// > &profile_with_bio = UserProfile {
// > age: 30,
// > username: "JohnDoe",
// > bio: Some( "Software Developer" ),
// > }
Run this example locally | Try it online
§Handling Optionals and Defaults
Former
makes working with optional fields and default values straightforward:
-
Option< T >
Fields: As seen in the basic example, fields of typeOption< T >
automatically default toNone
. You only need to call the setter if you have aSome( value )
. -
Custom Defaults: For required fields that don’t implement
Default
, or when you need a specific default value other than the type’s default, use the#[ former( default = ... ) ]
attribute:
use former::Former;
#[ derive( Debug, PartialEq, Former ) ]
pub struct Config
{
#[ former( default = 1024 ) ] // Use 1024 if .buffer_size() is not called
buffer_size : i32,
timeout : Option< i32 >, // Defaults to None
#[ former( default = true ) ] // Default for bool
enabled : bool,
}
// Only set the optional timeout
let config1 = Config::former()
.timeout( 5000 )
.form();
assert_eq!( config1.buffer_size, 1024 ); // Got default
assert_eq!( config1.timeout, Some( 5000 ) );
assert_eq!( config1.enabled, true ); // Got default
// Set everything, overriding defaults
let config2 = Config::former()
.buffer_size( 4096 )
.timeout( 1000 )
.enabled( false )
.form();
assert_eq!( config2.buffer_size, 4096 );
assert_eq!( config2.timeout, Some( 1000 ) );
assert_eq!( config2.enabled, false );
§Building Collections & Nested Structs (Subformers)
Where former
significantly simplifies complex scenarios is in building collections (Vec
, HashMap
, etc.) or nested structs. It achieves this through subformers. Instead of setting the entire collection/struct at once, you get a dedicated builder for the field:
Example: Building a Vec
use former::Former;
#[ derive( Debug, PartialEq, Former ) ]
pub struct Report
{
title : String,
#[ subform_collection( definition = former::VectorDefinition ) ] // Enables the `.entries()` subformer
entries : Vec< String >,
}
let report = Report::former()
.title( "Log Report".to_string() )
.entries() // Get the subformer for the Vec
.add( "Entry 1".to_string() ) // Use subformer methods to modify the Vec
.add( "Entry 2".to_string() )
.end() // Return control to the parent former (ReportFormer)
.form(); // Finalize the Report
assert_eq!( report.title, "Log Report" );
assert_eq!( report.entries, vec![ "Entry 1".to_string(), "Entry 2".to_string() ] );
dbg!( &report );
// > &report = Report {
// > title: "Log Report",
// > entries: [
// > "Entry 1",
// > "Entry 2",
// > ],
// > }
See Vec example | See HashMap example
former
provides different subform attributes (#[ subform_collection ]
, #[ subform_entry ]
, #[ subform_scalar ]
) for various collection and nesting patterns.
§Standalone Constructors
For scenarios where you want a direct constructor function instead of always starting with YourType::former()
, former
offers standalone constructors.
- Enable: Add
#[ standalone_constructors ]
to your struct or enum definition. - Function Name: A function named after your type (in
snake_case
) will be generated (e.g.,my_struct()
forstruct MyStruct
). For enums, functions are named after variants (e.g.,my_variant()
forenum E { MyVariant }
). - Arguments: By default, the constructor takes no arguments and returns the
Former
type. - Specify Arguments: Mark specific fields with
#[ arg_for_constructor ]
to make them required arguments for the standalone constructor. - Return Type (Option 2 Logic):
- If all fields of the struct/variant are marked with
#[ arg_for_constructor ]
, the standalone constructor returns the instance directly (Self
). - If zero or some fields are marked, the standalone constructor returns the
Former
type, pre-initialized with the provided arguments.
- If all fields of the struct/variant are marked with
Example: Struct Standalone Constructors
use former::Former;
#[ derive( Debug, PartialEq ) ] // Former not yet implemented for standalone_constructors
// #[ standalone_constructors ] // Enable standalone constructors
pub struct ServerConfig
{
#[ arg_for_constructor ] // This field is a constructor arg
host : String,
#[ arg_for_constructor ] // This field is also a constructor arg
port : u16,
timeout : Option< u32 >, // This field is NOT a constructor arg
}
// Not all fields are args, so `server_config` returns the Former
let config_former = server_config( "localhost".to_string(), 8080u16 ); // Added u16 suffix
// Set the remaining field and form
let config = config_former
.timeout( 5000u32 ) // Added u32 suffix
.form();
assert_eq!( config.host, "localhost" );
assert_eq!( config.port, 8080u16 ); // Added u16 suffix
assert_eq!( config.timeout, Some( 5000u32 ) ); // Added u32 suffix
#[ derive( Debug, PartialEq, Former ) ]
#[ standalone_constructors ]
pub struct Point
{
#[ arg_for_constructor ]
x : i32,
#[ arg_for_constructor ]
y : i32,
}
// ALL fields are args, so `point` returns Self directly
let p = point( 10, 20 );
assert_eq!( p.x, 10 );
assert_eq!( p.y, 20 );
Example: Enum Standalone Constructors
§Vocabulary & Terminology
Understanding the terminology used in former
will help you leverage its full potential, especially when working with enums and variants:
§Core Concepts
Former
: A builder object that accumulates field values and produces the final instance via.form()
.Storage
: Internal structure that holds the building state, containing options for each field.Subformer
: A specialized former for building nested structures, collections, or complex field types.FormingEnd
: A mechanism that controls what happens when.form()
is called on a (sub)former.
§Variant Types (for Enums)
- Unit Variant: An enum variant with no associated data (e.g.,
Status::Active
). - Tuple Variant: An enum variant with unnamed fields in parentheses (e.g.,
Message::Error(String)
,Point::Coords(i32, i32)
). - Struct Variant: An enum variant with named fields in braces (e.g.,
Request::Get { url: String, headers: Vec<String> }
).
§Variant Field Categories
- Zero-Field Variant: A variant with no fields - can be unit (
Status::Active
) or empty tuple (Status::Active()
). - Single-Field Variant: A variant with exactly one field (e.g.,
Message::Text(String)
orUser::Profile { name: String }
). - Multi-Field Variant: A variant with multiple fields (e.g.,
Point::Coords(i32, i32)
orRequest::Post { url: String, body: String }
).
§Constructor Types
- Scalar Constructor: A method that takes direct values and immediately returns the enum instance (e.g.,
Message::text("hello")
→Message::Text("hello")
). - Subform Constructor: A method that returns a former/builder for constructing the variant step-by-step, useful for complex variants.
- Direct Constructor: Simple constructor for variants with no fields (e.g.,
Status::active()
→Status::Active
).
§Enum Constructor Patterns
- Method-style Constructor: Instance methods on the enum type (e.g.,
MyEnum::variant_name(...)
). - Standalone Constructor: Top-level functions generated when
#[standalone_constructors]
is used (e.g.,variant_name(...)
).
§Variant Attributes
#[scalar]
: Forces generation of a scalar constructor that takes field values directly and returns the enum instance.#[subform_scalar]
: For single-field variants where the field type implementsFormer
- generates a method returning the field’s former.#[standalone_constructors]
: Applied to the enum itself, generates top-level constructor functions for each variant.#[arg_for_constructor]
: Applied to individual fields, includes them as parameters in standalone constructors.
§Advanced Concepts
- Implicit Variant Former: An automatically generated former for variants with multiple fields, providing individual field setters.
- End-of-forming Logic: Custom behavior when a former completes, enabling advanced patterns like validation or transformation.
- Context Propagation: Mechanism for passing data through nested formers in complex builder hierarchies.
§Key Features Overview
- Automatic Builder Generation:
#[ derive( Former ) ]
for structs and enums. - Fluent API: Chainable setter methods for a clean construction flow.
- Comprehensive Enum Support: Full support for all enum variant types:
- Unit variants: Direct constructors (e.g.,
MyEnum::variant()
) - Tuple variants: Scalar constructors or subformers based on field count and attributes
- Struct variants: Subformers with individual field setters or scalar constructors
- Zero, single, and multi-field variants with different behavioral patterns
- Unit variants: Direct constructors (e.g.,
- Flexible Constructor Generation:
- Method-style constructors:
MyEnum::variant_name(...)
on the enum type - Standalone constructors: Top-level functions when
#[standalone_constructors]
is used - Scalar constructors: Direct value-to-instance conversion with
#[scalar]
- Subform constructors: Builder pattern for complex variants
- Method-style constructors:
- Defaults & Optionals: Seamless handling of
Default
values andOption< T >
fields. Custom defaults via#[ former( default = ... ) ]
. - Subformers: Powerful mechanism for building nested structures and collections:
#[ subform_scalar ]
: For fields whose type also derivesFormer
, or for single-field enum variants#[ subform_collection ]
: For collections likeVec
,HashMap
,HashSet
, etc., providing methods like.add()
or.insert()
#[ subform_entry ]
: For collections where each entry is built individually using its own former
- Variant-Specific Attributes:
#[ scalar ]
: Forces scalar constructor generation for enum variants#[ subform_scalar ]
: Enables subformer delegation for compatible variants#[ standalone_constructors ]
: Generates top-level constructor functions#[ arg_for_constructor ]
: Controls parameter inclusion in standalone constructors
- Customization:
- Rename setters:
#[ scalar( name = ... ) ]
,#[ subform_... ( name = ... ) ]
- Disable default setters:
#[ scalar( setter = false ) ]
,#[ subform_... ( setter = false ) ]
- Define custom setters directly in
impl Former
- Specify collection definitions:
#[ subform_collection( definition = ... ) ]
- Rename setters:
- Advanced Control:
- Storage-only fields:
#[ storage_fields( ... ) ]
. - Custom mutation logic:
#[ mutator( custom ) ]
+impl FormerMutator
. - Custom end-of-forming logic: Implement
FormingEnd
. - Custom collection support: Implement
Collection
traits.
- Storage-only fields:
§Where to Go Next
- Advanced Usage & Concepts: Dive deeper into subformers, customization options, storage, context, definitions, mutators, and custom collections.
- Examples Directory: Explore practical, runnable examples showcasing various features.
- API Documentation (docs.rs): Get detailed information on all public types, traits, and functions.
- Repository (GitHub): View the source code, contribute, or report issues.
Modules§
- dependency
- Namespace with dependencies
- derive
- Former Meta - Procedural Macro Implementation
- exposed
- Exposed namespace of the module
- orphan
- Parented namespace of the module
- own
- Own namespace of the module
- prelude
- Prelude to use essentials
Structs§
- BTree
MapDefinition - Represents the formation definition for a hash map-like collection within the former framework.
- BTree
MapDefinition Types - Holds the generic parameters for the
BTreeMapDefinition
. - BTree
SetDefinition - Represents the formation definition for a binary tree set-like collection within the former framework.
- BTree
SetDefinition Types - Holds the generic parameters for the
BTreeSetDefinition
. - Binary
Heap Definition - Represents the formation definition for a binary heap-like collection within the former framework.
- Binary
Heap Definition Types - Holds the generic parameters for the
BinaryHeapDefinition
. - Collection
Former - A builder structure for constructing collections with a fluent and flexible interface.
- Forming
EndClosure - A wrapper around a closure to be used as a
FormingEnd
. - Hash
MapDefinition - Represents the formation definition for a hash map-like collection within the former framework.
- Hash
MapDefinition Types - Holds the generic parameters for the
HashMapDefinition
. - Hash
SetDefinition - Represents the formation definition for a hash set-like collection within the former framework.
- Hash
SetDefinition Types - Holds the generic parameters for the
HashSetDefinition
. - Linked
List Definition - Represents the formation definition for a list-like collection within the former framework.
- Linked
List Definition Types - Holds the generic parameters for the
LinkedListDefinition
. - NoEnd
- A placeholder
FormingEnd
used when no end operation is required or applicable. - Return
Preformed - A
FormingEnd
implementation that directly returns the formed collection as the final product of the forming process. - Return
Storage - A
FormingEnd
implementation that returns the storage itself as the formed entity, disregarding any contextual data. - VecDeque
Definition - Represents the formation definition for a vector deque-like collection within the former framework.
- VecDeque
Definition Types - Holds the generic parameters for the
VecDequeDefinition
. - Vector
Definition - Represents the formation definition for a vector-like collection within the former framework.
- Vector
Definition Types - Holds the generic parameters for the
VectorDefinition
.
Traits§
- BTree
MapExt - Provides an extension method for hash maps to facilitate the use of the builder pattern.
- BTree
SetExt - Provides an extension method for binary tree sets to facilitate the use of the builder pattern.
- Binary
Heap Ext - Provides an extension method for binary heaps to facilitate the use of the builder pattern.
- Collection
- Represents a collection by defining the types of entries and values it handles.
- Collection
Add - Provides functionality to add individual entries to a collection.
- Collection
Assign - Defines the capability to replace all entries in a collection with a new set of entries.
- Collection
ValTo Entry - Provides a mechanism for transforming a value back into a collection-specific entry format.
- Entity
ToDefinition - Maps a type of entity to its corresponding former definition.
- Entity
ToDefinition Types - Provides a mapping between a type of entity and its associated formation type definitions.
- Entity
ToFormer - Maps a type of entity to its corresponding former (builder) implementation.
- Entity
ToStorage - Maps a type of entity to its storage type. This trait defines what storage structure is used to hold the interim state of an entity during its formation.
- Entry
ToVal - Facilitates the conversion of collection entries to their corresponding value representations.
- Former
Begin - A trait for initiating a structured subforming process with contextual and intermediary storage linkage.
- Former
Definition - Expands on
FormerDefinitionTypes
by incorporating an ending mechanism for the formation process. This trait connects the formation types with a specific endpoint, defining how the formation process concludes, including any necessary transformations or validations. - Former
Definition Types - Defines the fundamental components involved in the formation of an entity. This trait specifies the types of storage, the formed entity, and the context used during the formation process.
- Former
Mutator - Provides a mechanism for mutating the context and storage just before the forming process is completed.
- Forming
End - Defines a handler for the end of a subforming process, enabling the return of the original context.
- Hash
MapExt - Provides an extension method for hash maps to facilitate the use of the builder pattern.
- Hash
SetExt - Provides an extension method for
HashSet
to facilitate the use of the builder pattern. - Linked
List Ext - Provides an extension method for lists to facilitate the use of the builder pattern.
- Storage
- Defines the storage interface for entities being constructed using a forming pattern.
- Storage
Preform - Provides a mechanism to finalize the forming process by converting storage into its final formed state.
- ValTo
Entry - Facilitates the conversion of values back into entries for specific collection types.
- VecDeque
Ext - Provides an extension method for vector deques to facilitate the use of the builder pattern.
- VecExt
- Provides an extension method for vectors to facilitate the use of the builder pattern.
Type Aliases§
- BTree
MapFormer - Provides a streamlined builder interface for constructing hash map-like collections.
- BTree
SetFormer - Provides a streamlined builder interface for constructing binary tree set-like collections.
- Binary
Heap Former - Provides a streamlined builder interface for constructing binary heap-like collections.
- Hash
MapFormer - Provides a streamlined builder interface for constructing hash map-like collections.
- Hash
SetFormer - Provides a concise alias for
CollectionFormer
configured specifically forHashSet
-like collections. - Linked
List Former - Provides a streamlined builder interface for constructing list-like collections.
- VecDeque
Former - Provides a streamlined builder interface for constructing vector deque-like collections.
- Vector
Former - Provides a streamlined builder interface for constructing vector-like collections.
Derive Macros§
- Former
- Derive macro for generating a
Former
struct, applying a Builder Pattern to the annotated struct.