tomoikey
typesafe_builder
Rust

๐Ÿš€ The Ultimate Builder Pattern Implementation Powered by Rust's Type System. Type safety is not a luxury, it's a necessity.

Last updated Apr 10, 2026
35
Stars
2
Forks
1
Issues
0
Stars/day
Attention Score
6
Language breakdown
Rust 100.0%
โ–ธ Files click to expand
README

TypeSafe Builder

crates.io downloads license rustc

Compile-Time Type Safety โ€ข Zero Runtime Cost โ€ข Blazing Fast Builds

The Ultimate Builder Pattern Implementation Powered by Rust's Type System

Eliminate bugs at the type level and revolutionize your development experience


Why TypeSafe Builder?

Traditional builder patterns can't detect missing required fields until runtime. TypeSafe Builder leverages Rust's powerful type system to verify all constraints at compile time.

// โŒ Traditional builder - potential runtime errors
let user = UserBuilder::new()
    .name("Alice")
    .build()?; // Compiles even with missing required fields

// โœ… TypeSafe Builder - compile-time safety guarantee let user = UserBuilder::new() .withname("Alice".tostring()) .withemail("alice@example.com".tostring()) // Compile error if email is required .build(); // Always guaranteed to succeed

Key Features

Type-Level Constraint System

  • Required Fields - Completely prevent missing required field configuration
  • Optional Fields - Freely configurable fields
  • Default Values - Fields with intelligent default values using Default::default() or custom expressions
  • Conditional Requirements - Express dynamic dependencies at the type level
  • Complex Logic - Support for AND/OR/NOT operators in complex conditional expressions
  • Into Conversion - Ergonomic setters with automatic type conversion via Into<T>

Performance Characteristics

  • Zero Runtime Cost - All validation completed at compile time

Safety Guarantees

  • No Panic - Complete elimination of runtime panics

Quick Start

[dependencies]
typesafe_builder = "..*" # Replace with the actual version
use typesafe_builder::*;

#[derive(Builder)] struct User { #[builder(required)] name: String, #[builder(optional)] age: Option<u32>, #[builder(default = "String::from(\"user@example.com\")")] email: String, #[builder(default)] active: bool, }

// Type-safe builder pattern let user = UserBuilder::new() .withname("Alice".tostring()) .with_age(30) .build(); // email will be "user@example.com", active will be false

Advanced Features

1. Conditional Required Fields

use typesafe_builder::*;

#[derive(Builder)] struct Account { #[builder(optional)] email: Option<String>, #[builder(required_if = "email")] // Required when email is set email_verified: Option<bool>, }

// โœ… Compiles successfully let account1 = AccountBuilder::new().build();

// โœ… Compiles successfully let account2 = AccountBuilder::new() .withemail("user@example.com".tostring()) .withemailverified(true) .build();

// โŒ Compile error: email_verified is not set // let account3 = AccountBuilder::new() // .withemail("user@example.com".tostring()) // .build();

2. Conditional Optional Fields

use typesafe_builder::*;

#[derive(Builder)] struct Config { #[builder(optional)] debug_mode: Option<bool>, #[builder(optionalif = "debugmode")] // Required when debug_mode is not set log_level: Option<String>, }

// โœ… When debugmode is not set, loglevel is required let config1 = ConfigBuilder::new() .withloglevel("INFO".to_string()) .build();

// โœ… When debugmode is set, loglevel is optional let config2 = ConfigBuilder::new() .withdebugmode(true) .build();

3. Complex Conditional Logic

use typesafe_builder::*;

#[derive(Builder)] struct ApiClient { #[builder(optional)] use_auth: Option<bool>, #[builder(optional)] use_https: Option<bool>, #[builder(optional)] api_key: Option<String>,

// Secret is required if using auth OR HTTPS #[builder(requiredif = "useauth || use_https")] secret: Option<String>,

// Certificate is required only when using both auth AND HTTPS #[builder(requiredif = "useauth && use_https")] certificate: Option<String>,

// Warning is required when using neither auth NOR HTTPS #[builder(requiredif = "!useauth && !use_https")] insecure_warning: Option<String>,

// Complex condition: Token required when (auth OR HTTPS) AND (no API key) #[builder(requiredif = "(useauth || usehttps) && !apikey")] fallback_token: Option<String>, }

// โœ… All dependencies satisfied (auth + HTTPS) let client1 = ApiClientBuilder::new() .withuseauth(true) .withusehttps(true) .withapikey("key123".to_string()) .withsecret("secret456".tostring()) .withcertificate("cert.pem".tostring()) .build();

// โœ… Insecure configuration with warning let client2 = ApiClientBuilder::new() .withuseauth(false) .withusehttps(false) .withinsecurewarning("WARNING: Insecure connection!".to_string()) .build();

// โœ… Using fallback token when API key is not set let client3 = ApiClientBuilder::new() .withuseauth(true) .withsecret("secret".tostring()) .withfallbacktoken("backuptoken".tostring()) .build();

4. Default Values

TypeSafe Builder supports two ways to specify default values:

Simple Default Values (using Default::default())

use typesafe_builder::*;

#[derive(Builder)] struct Config { // Uses String::default() (empty string) #[builder(default)] name: String,

// Uses i32::default() (0) #[builder(default)] port: i32,

// Uses bool::default() (false) #[builder(default)] enabled: bool,

// Uses Vec::default() (empty vector) #[builder(default)] items: Vec<String>,

// Uses HashMap::default() (empty map) #[builder(default)] metadata: std::collections::HashMap<String, String>,

// Works with custom types that implement Default #[builder(default)] custom_field: MyCustomType,

#[builder(required)] service_name: String, }

// โœ… Use default values let config = ConfigBuilder::new() .withservicename("my-service".to_string()) .build(); // name: "", port: 0, enabled: false, items: [], metadata: {}, custom_field: MyCustomType::default()

Custom Default Expressions

use typesafe_builder::*;

#[derive(Builder)] struct ServerConfig { #[builder(default = "String::from(\"localhost\")")] host: String,

#[builder(default = "8080")] port: u16,

#[builder(default = "vec![\"GET\".tostring(), \"POST\".tostring()]")] allowed_methods: Vec<String>,

#[builder(default = "std::collections::HashMap::new()")] headers: std::collections::HashMap<String, String>,

#[builder(required)] service_name: String,

#[builder(optional)] ssl_cert: Option<String>, }

// โœ… Use default values let config1 = ServerConfigBuilder::new() .withservicename("my-api".to_string()) .build(); // host: "localhost", port: 8080, allowed_methods: ["GET", "POST"], headers: {}

// โœ… Override some defaults let config2 = ServerConfigBuilder::new() .withservicename("my-api".to_string()) .withhost("0.0.0.0".tostring()) .with_port(3000) .build(); // host: "0.0.0.0", port: 3000, allowed_methods: ["GET", "POST"], headers: {}

// โœ… Complex default expressions #[derive(Builder)] struct AppConfig { #[builder(default = "std::env::var(\"APPNAME\").unwraporelse(|| \"default-app\".to_string())")] app_name: String,

#[builder(default = "chrono::Utc::now()")] created_at: chrono::DateTime<chrono::Utc>,

#[builder(default = "uuid::Uuid::new_v4()")] instance_id: uuid::Uuid, }

Mixed Default Types

use typesafe_builder::*;

#[derive(Builder)] struct MixedConfig { // Simple default (uses Default::default()) #[builder(default)] name: String,

// Custom expression default #[builder(default = "42")] port: i32,

// Simple default for collections #[builder(default)] tags: Vec<String>,

// Custom expression for complex initialization #[builder(default = "std::collections::HashMap::from([(\"key\".tostring(), \"value\".tostring())])")] metadata: std::collections::HashMap<String, String>, }

let config = MixedConfigBuilder::new().build(); // name: "", port: 42, tags: [], metadata: {"key": "value"}

Key features of default values:

  • Simple defaults: Use #[builder(default)] for types implementing Default
  • Custom expressions: Use #[builder(default = "expression")] for any valid Rust expression
  • No type restrictions: Works with primitives, collections, function calls, etc.
  • Environment variables: Access environment variables at build time (custom expressions)
  • Function calls: Call any function or method as default value (custom expressions)
  • Standalone attribute: Cannot be combined with required, optional, etc.
  • Zero runtime cost: All defaults are computed at build time

5. Negation Operator Support

use typesafe_builder::*;

#[derive(Builder)] struct Database { #[builder(optional)] use_ssl: Option<bool>,

// Warning message required when NOT using SSL #[builder(requiredif = "!usessl")] warning_message: Option<String>, }

// โœ… Warning configuration for non-SSL usage let db = DatabaseBuilder::new() .withusessl(false) .withwarningmessage("Insecure connection!".to_string()) .build();

6. Into Conversion Support

The #[builder(into)] attribute allows setter methods to accept any type that implements Into<T> for the field type T, providing more ergonomic APIs:

use typesafe_builder::*;

#[derive(Builder)] struct User { #[builder(required)] #[builder(into)] name: String,

#[builder(optional)] #[builder(into)] email: Option<String>, }

// โœ… Accept &str directly (converts to String via Into) let user1 = UserBuilder::new() .with_name("Alice") // &str -> String .with_email("alice@example.com") // &str -> String .build();

// โœ… Still works with String directly let user2 = UserBuilder::new() .withname("Bob".tostring()) .build();

Key benefits:

  • Ergonomic APIs: Accept &str for String fields without manual conversion
  • Type flexibility: Any Into<T> implementation works automatically
  • Zero overhead: Conversion happens at the call site
  • Backward compatible: Works alongside existing setter patterns

7. Custom Builder Name

use typesafe_builder::*;

#[derive(Builder)] #[builder(name = "MyCustomBuilder")] // Customize the builder name struct User { #[builder(required)] name: String, }

// Use the customized builder name let user = MyCustomBuilder::new() .withname("Alice".tostring()) .build();

Error Handling

Compile-Time Error Examples

#[derive(Builder)]
struct User {
    #[builder(required)]
    name: String,
}

// โŒ Compile error let user = UserBuilder::new().build(); // ^^^^^ // error: no method named build found for struct UserBuilder&lt;_TypesafeBuilderEmpty&gt; // method build is available on UserBuilder&lt;_TypesafeBuilderFilled&gt;

Constraint Violation Error Examples

#[derive(Builder)]
struct Config {
    #[builder(optional)]
    feature: Option<bool>,
    #[builder(required_if = "feature")]
    config: Option<String>,
}

// โŒ Compile error let config = ConfigBuilder::new() .with_feature(true) .build(); // ^^^^^ // error: no method named build found for struct ConfigBuilder&lt;TypesafeBuilderFilled, TypesafeBuilderEmpty&gt; // method build is available on ConfigBuilder&lt;TypesafeBuilderFilled, TypesafeBuilderFilled&gt;

Real-World Use Cases

Web API Configuration

#[derive(Builder)]
struct ApiConfig {
    #[builder(required)]
    base_url: String,

#[builder(optional)] use_auth: Option<bool>,

#[builder(requiredif = "useauth")] api_key: Option<String>,

#[builder(requiredif = "useauth")] secret: Option<String>,

#[builder(default = "30")] timeout_seconds: u64,

#[builder(default = "String::from(\"application/json\")")] content_type: String, }

Database Connection

#[derive(Builder)]
struct DatabaseConfig {
    #[builder(required)]
    host: String,

#[builder(required)] database: String,

#[builder(default = "5432")] port: u16,

#[builder(default = "10")] max_connections: u32,

#[builder(optional)] use_ssl: Option<bool>,

#[builder(requiredif = "usessl")] sslcertpath: Option<String>,

#[builder(optionalif = "!usessl")] allow_insecure: Option<bool>, }

Contributing

We welcome contributions to TypeSafe Builder!

Development Environment Setup

git clone https://github.com/tomoikey/typesafe_builder.git
cd typesafe_builder
cargo test

Running Tests

# Run all tests
cargo test

UI tests (compile error verification)

cargo test --package typesafebuilderderive --test ui

Contributors

Amazing developers who have contributed to this project:

tomoikey
tomoikey
Creator & Maintainer
ramsyana
ramsyana
Contributor
You?
Your Name Here
Next Contributor

Want to see your name here? Contribute now and join our amazing community!

Contributors

License

MIT License - see the LICENSE file for details.

Give us a star!

If you find this project useful, please consider giving it a star!


Made with โค๏ธ by Rust community
Type safety is not a luxury, it's a necessity.

๐Ÿ”— More in this category

ยฉ 2026 GitRepoTrend ยท tomoikey/typesafe_builder ยท Updated daily from GitHub