Expand description
Β§Module :: component_model
Revolutionary type-safe component assignment for Rust. Build complex objects with zero boilerplate using derive macros and type-driven field setting. Perfect for configuration builders, fluent APIs, and object composition patterns.
Β§π Why Component Model?
Traditional struct initialization is verbose and error-prone:
// Traditional approach - repetitive and fragile
let config = Config
{
host : "localhost".to_string(),
port : 8080,
};
// Builder pattern - lots of boilerplate
let config = ConfigBuilder::new()
.host( "localhost" )
.port( 8080 )
.build();
Component Model approach - Clean, type-safe, zero boilerplate:
use component_model::Assign;
#[ derive( Default, Assign ) ]
struct Config
{
host : String,
port : i32,
}
// Set components by type - no field names needed!
let mut config = Config::default();
config.assign( "localhost" ); // Automatically sets String field
config.assign( 8080 ); // Automatically sets i32 field
// Or use fluent style
let config = Config::default()
.impute( "localhost" )
.impute( 8080 );
Β§β¨ Key Features
- π― Type-driven assignment - Set fields by component type, not field name
- π§ Zero boilerplate - Derive macros generate all implementations automatically
- π Fluent APIs - Chainable
impute()
method for builder patterns - π‘οΈ Type safety - All assignments checked at compile time
- π Flexible conversion - Accepts any type convertible to target field type
- π¦ Multiple assignment - Set multiple components with
ComponentsAssign
- β‘ Popular types support - Built-in support for Duration, PathBuf, SocketAddr, and more
- ποΈ ComponentModel derive - Unified derive macro combining all functionality
Β§π Quick Start
Add to your Cargo.toml
:
[ dependencies ]
component_model = "0.4"
Β§Feature Flags
Component Model follows granular feature gating for minimal builds:
[ dependencies ]
# Minimal version - no features enabled by default
component_model = { version = "0.4", default-features = false }
# Enable specific features as needed
component_model = { version = "0.4", features = [ "derive_component_model" ] }
# Or enable all features (default)
component_model = { version = "0.4", features = [ "full" ] }
Available features:
enabled
- Master switch for core functionalityfull
- All features (enabled by default)derive_component_model
- Unified ComponentModel derive macroderive_component_assign
- Basic Assign derive macroderive_components_assign
- Multiple component assignmentderive_component_from
- Component creation from single valuesderive_from_components
- Component creation from multiple values
Β§π Core Concepts
Β§1. Basic Assignment with ComponentModel
use component_model::{ ComponentModel, Assign };
#[ derive( Default, Debug, ComponentModel ) ]
struct Person
{
age : i32,
name : String,
}
fn main()
{
let mut person = Person::default();
// Type-driven assignment - no field names!
person.assign( 25 ); // Sets age : i32
person.assign( "Alice" ); // Sets name : String
println!( "{:?}", person ); // Person { age: 25, name: "Alice" }
}
Β§2. Popular Types Support
ComponentModel provides built-in support for popular Rust types with intelligent conversion:
use component_model::{ ComponentModel, Assign };
use std::time::Duration;
use std::path::PathBuf;
#[ derive( Default, Debug, ComponentModel ) ]
struct Config
{
timeout : Duration,
config_path : PathBuf,
port : i32,
}
fn main()
{
let mut config = Config::default();
// Duration from seconds (u64)
config.assign( 30u64 ); // Duration::from_secs( 30 )
// Duration from fractional seconds (f64)
config.assign( 2.5f64 ); // Duration::from_secs_f64( 2.5 )
// PathBuf from string slice
config.assign( "/etc/app.conf" ); // PathBuf::from( "/etc/app.conf" )
// i32 assignment
config.assign( 8080i32 );
}
Β§3. Enum Fields in Structs
ComponentModel works with structs that contain enum fields, enabling type-safe enum assignment:
use component_model::{ ComponentModel, Assign };
#[ derive( Debug, PartialEq ) ]
enum Status
{
Pending,
Processing { progress : f64 },
Completed { result : String },
Failed { error : String },
}
impl Default for Status
{
fn default() -> Self { Status::Pending }
}
#[ derive( Default, Debug, ComponentModel ) ]
struct Task
{
id : u32,
status : Status,
priority : u8,
}
fn main()
{
let mut task = Task::default();
// Use field-specific methods with enums
task.id_set( 42u32 );
task.priority_set( 5u8 );
task.status_set( Status::Processing { progress: 0.75 } );
println!( "{:?}", task );
// Fluent style with enums
let completed_task = Task::default()
.id_with( 100u32 )
.status_with( Status::Completed { result: "Success".to_string() } )
.priority_with( 1u8 );
match completed_task.status {
Status::Completed { result } => println!( "Task completed: {}", result ),
_ => println!( "Unexpected status" ),
}
}
Β§Complex Enum Fields
use component_model::{ ComponentModel, Assign };
use std::time::Duration;
#[ derive( Debug ) ]
enum ConnectionState
{
Disconnected,
Connecting { timeout : Duration },
Connected { session_id : String },
}
impl Default for ConnectionState
{
fn default() -> Self { ConnectionState::Disconnected }
}
#[ derive( Default, Debug, ComponentModel ) ]
struct NetworkService
{
name : String,
state : ConnectionState,
retry_count : u32,
}
fn main()
{
let mut service = NetworkService::default();
// Field-specific methods work seamlessly with enum fields
service.name_set( "WebSocket".to_string() );
service.retry_count_set( 3u32 );
service.state_set( ConnectionState::Connected {
session_id: "sess_12345".to_string()
} );
// Fluent pattern with complex enums
let connecting_service = NetworkService::default()
.name_with( "HTTP Client".to_string() )
.state_with( ConnectionState::Connecting {
timeout: Duration::from_secs( 30 )
} )
.retry_count_with( 0u32 );
println!( "{:?}", connecting_service );
}
Note: Direct ComponentModel derive on enums is planned for future releases. Currently, enums work as field types in structs with ComponentModel.
Β§4. Fluent Builder Pattern
let person = Person::default()
.impute( "Bob" ) // Chainable assignment
.impute( 30 ); // Returns Self for chaining
Β§5. Multiple Component Assignment
use component_model::{ ComponentModel, Assign };
#[ derive( Default, ComponentModel ) ]
struct ServerConfig
{
host : String,
port : i32,
}
let mut config = ServerConfig::default();
config.assign( "localhost" ); // String component
config.assign( 8080 ); // i32 component
Β§6. Manual Implementation (Advanced)
For custom behavior, implement traits manually:
use component_model::prelude::*;
struct Database
{
url : String,
pool_size : usize,
}
impl< T : Into< String > > Assign< String, T > for Database
{
fn assign( &mut self, component : T )
{
self.url = component.into();
}
}
impl< T : Into< usize > > Assign< usize, T > for Database
{
fn assign( &mut self, component : T )
{
self.pool_size = component.into();
}
}
Β§π Available Derive Macros
ComponentModel
- β Recommended - Unified derive combining all functionalityAssign
- Basic component assignment by typeComponentsAssign
- Multiple component assignment from tuplesComponentFrom
- Create objects from single componentsFromComponents
- Create objects from multiple components
Β§π― Real-World Use Cases
Β§Configuration Management with Popular Types
use component_model::{ ComponentModel, Assign };
use std::time::Duration;
use std::path::PathBuf;
#[ derive( Default, ComponentModel ) ]
struct DatabaseConfig
{
host : String,
port : i32,
timeout : Duration,
}
let config = DatabaseConfig::default()
.impute( "postgres.example.com" ) // String
.impute( 5432 ) // i32
.impute( 30u64 ); // Duration from seconds
Β§HTTP Client Builders
use component_model::{ ComponentModel, Assign };
use std::time::Duration;
#[ derive( Default, ComponentModel ) ]
struct HttpClient
{
base_url : String,
timeout : Duration,
}
let client = HttpClient::default()
.impute( "https://api.example.com" )
.impute( 30.0f64 ); // Duration from fractional seconds
Β§Game Entity Systems
use component_model::{ ComponentModel, Assign };
#[ derive( Default, ComponentModel ) ]
struct Player
{
name : String,
level : i32,
}
// Initialize components
let mut player = Player::default();
player.assign( "Hero" );
player.assign( 1 );
Β§π§ͺ Examples
Explore the examples directory for comprehensive usage patterns:
000_basic_assignment.rs
- Basic component assignment001_fluent_builder.rs
- Fluent builder pattern002_multiple_components.rs
- Multiple component handling003_component_from.rs
- Component creation patterns004_working_example.rs
- Real-world usage scenarioscomponent_model_trivial.rs
- Minimal example
Β§π Supported Popular Types
ComponentModel includes built-in intelligent conversion for:
Type | Input Types | Example |
---|---|---|
Duration | u64 , f64 , (u64, u32) | config.assign( 30u64 ) |
PathBuf | &str , String | config.assign( "/path/file" ) |
SocketAddr | Coming soon | String parsing planned |
HashMap | Framework ready | Vec conversion planned |
HashSet | Framework ready | Vec conversion planned |
Β§β οΈ Important Limitations
Type Ambiguity: When a struct has multiple fields of the same type, assign()
becomes ambiguous and wonβt compile. This is by design for type safety.
struct Config
{
host : String,
database : String, // Multiple String fields cause ambiguity
}
// This won't compile due to ambiguity:
// let mut config = Config::default();
// config.assign( "localhost" ); // Error: which String field?
Workarounds:
- Use different types when possible (e.g.,
String
vsPathBuf
) - Use direct field assignment:
config.host = "localhost".to_string();
- Implement manual
Assign
traits for specific use cases
Β§π Learn More
- π Examples - Step-by-step examples showing all features
- π API Docs - Complete API reference
- π Source Code - Contribute or report issues
- π¬ Discord - Get help and discuss
Made with β€οΈ as part of the wTools ecosystem
ModulesΒ§
- dependency
- Namespace with dependencies.
- derive
- Component model macro support
- exposed
- Exposed namespace of the module.
- orphan
- Parented namespace of the module.
- own
- Own namespace of the module.
- popular_
types - Popular type support for common Rust types. Popular type support for component model
- prelude
- Prelude to use essentials:
use my_module::prelude::*
. - std_
types - Standard library type support
TraitsΒ§
- Assign
- Provides a generic interface for setting a component of a certain type on an object.
- Assign
With Type - The
AssignWithType
trait provides a mechanism to set a component on an object, utilizing the type information explicitly. This trait extends the functionality ofAssign
by allowing implementers to specify the componentβs type at the method call site, enhancing expressiveness in code that manipulates object states. - Option
Ext - Extension trait to provide a method for setting a component on an
Option< Self >
if theOption
is currentlyNone
. If theOption
isSome
, the method will delegate to theAssign
traitβsassign
method. - Popular
Type - Marker trait to identify types that should get popular type support
Derive MacrosΒ§
- Assign
- Derives the
Assign
trait for struct fields, allowing each field to be set with a value that can be converted into the fieldβs type. - Component
From - Macro to implement
From
for each component (field) of a structure. This macro simplifies the creation ofFrom
trait implementations for struct fields, enabling easy conversion from a struct reference to its field types. - Component
Model - Unified derive macro that combines all component model functionality into a single annotation.
- Components
Assign - Derives the
ComponentsAssign
trait for a struct, enablingcomponents_assign
which set all fields at once. - From
Components - A procedural macro to automatically derive the
From<T>
trait implementation for a struct, enabling instances of one type to be converted from instances of another type.