use type_state_builder::TypeStateBuilder;
#[derive(TypeStateBuilder, Debug, PartialEq)]
struct UserProfile {
#[builder(required)]
username: String,
bio: Option<String>,
#[builder(converter = |value: &str| Some(value.to_string()))]
display_name: Option<String>,
#[builder(converter = |value: &str| Some(value.to_string()))]
location: Option<String>,
#[builder(converter = |value: u32| Some(value))]
age: Option<u32>,
#[builder(converter = |tags: Vec<&str>| Some(tags.into_iter().map(|s| s.to_string()).collect()))]
interests: Option<Vec<String>>,
}
#[derive(TypeStateBuilder, Debug, PartialEq)]
struct ServerConfig {
#[builder(required)]
host: String,
#[builder(required)]
port: u16,
#[builder(converter = |url: &str| Some(url.to_string()))]
database_url: Option<String>,
#[builder(converter = |path: &str| Some(path.to_string()))]
ssl_cert_path: Option<String>,
#[builder(converter = |count: u32| Some(count.clamp(1, 100)))]
worker_count: Option<u32>,
}
fn main() {
println!("=== Option Ergonomics with Converters ===");
let profile_verbose = UserProfile::builder()
.username("alice".to_string())
.bio(Some("Software developer".to_string())) .display_name("Alice Smith") .location("San Francisco") .age(29) .interests(vec!["rust", "programming"]) .build();
let profile_clean = UserProfile::builder()
.username("bob".to_string())
.bio(Some("Product manager".to_string())) .display_name("Bob Johnson") .location("New York") .age(35) .interests(vec!["management", "strategy"]) .build();
println!("Verbose profile: {profile_verbose:#?}");
println!("Clean profile: {profile_clean:#?}");
assert_eq!(profile_clean.display_name, Some("Bob Johnson".to_string()));
assert_eq!(profile_clean.location, Some("New York".to_string()));
assert_eq!(profile_clean.age, Some(35));
assert_eq!(
profile_clean.interests,
Some(vec!["management".to_string(), "strategy".to_string()])
);
println!("\n=== Server Configuration ===");
let config = ServerConfig::builder()
.host("localhost".to_string())
.port(8080)
.database_url("postgresql://user:pass@localhost/mydb") .ssl_cert_path("/etc/ssl/cert.pem") .worker_count(150) .build();
println!("Server config: {config:#?}");
assert_eq!(
config.database_url,
Some("postgresql://user:pass@localhost/mydb".to_string())
);
assert_eq!(config.ssl_cert_path, Some("/etc/ssl/cert.pem".to_string()));
assert_eq!(config.worker_count, Some(100));
println!("\n=== Benefits Summary ===");
println!("✅ No more verbose Some(value.to_string()) calls");
println!("✅ Direct value passing with automatic Option wrapping");
println!("✅ Can combine with validation logic (like worker_count clamping)");
println!("✅ Works with any type that implements Into<T>");
println!("✅ Maintains type safety and compile-time validation");
println!("\n✓ Option ergonomics example completed successfully!");
}