typesafe_builder 1.3.0

A procedural macro to generate type-safe builder patterns for Rust structs
Documentation

🦀 TypeSafe Builder 🦀

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()
    .with_name("Alice".to_string())
    .with_email("alice@example.com".to_string()) // 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
  • Conditional Requirements - Express dynamic dependencies at the type level
  • Complex Logic - Support for AND/OR/NOT operators in complex conditional expressions

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>,
}

// Type-safe builder pattern
let user = UserBuilder::new()
    .with_name("Alice".to_string())
    .with_age(30)
    .build();

🚀 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()
    .with_email("user@example.com".to_string())
    .with_email_verified(true)
    .build();

// ❌ Compile error: email_verified is not set
// let account3 = AccountBuilder::new()
//     .with_email("user@example.com".to_string())
//     .build();

2️⃣ Conditional Optional Fields

use typesafe_builder::*;

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

// ✅ When debug_mode is not set, log_level is required
let config1 = ConfigBuilder::new()
    .with_log_level("INFO".to_string())
    .build();

// ✅ When debug_mode is set, log_level is optional
let config2 = ConfigBuilder::new()
    .with_debug_mode(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(required_if = "use_auth || use_https")]
    secret: Option<String>,
    
    // Certificate is required only when using both auth AND HTTPS
    #[builder(required_if = "use_auth && use_https")]
    certificate: Option<String>,
    
    // Warning is required when using neither auth NOR HTTPS
    #[builder(required_if = "!use_auth && !use_https")]
    insecure_warning: Option<String>,
    
    // Complex condition: Token required when (auth OR HTTPS) AND (no API key)
    #[builder(required_if = "(use_auth || use_https) && !api_key")]
    fallback_token: Option<String>,
}

// ✅ All dependencies satisfied (auth + HTTPS)
let client1 = ApiClientBuilder::new()
    .with_use_auth(true)
    .with_use_https(true)
    .with_api_key("key123".to_string())
    .with_secret("secret456".to_string())
    .with_certificate("cert.pem".to_string())
    .build();

// ✅ Insecure configuration with warning
let client2 = ApiClientBuilder::new()
    .with_use_auth(false)
    .with_use_https(false)
    .with_insecure_warning("WARNING: Insecure connection!".to_string())
    .build();

// ✅ Using fallback token when API key is not set
let client3 = ApiClientBuilder::new()
    .with_use_auth(true)
    .with_secret("secret".to_string())
    .with_fallback_token("backup_token".to_string())
    .build();

4️⃣ Negation Operator Support

use typesafe_builder::*;

#[derive(Builder)]
struct Database {
    #[builder(optional)]
    use_ssl: Option<bool>,
    
    // Warning message required when NOT using SSL
    #[builder(required_if = "!use_ssl")]
    warning_message: Option<String>,
}

// ✅ Warning configuration for non-SSL usage
let db = DatabaseBuilder::new()
    .with_use_ssl(false)
    .with_warning_message("Insecure connection!".to_string())
    .build();

5️⃣ 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()
    .with_name("Alice".to_string())
    .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<_TypesafeBuilderEmpty>`
//        method `build` is available on `UserBuilder<_TypesafeBuilderFilled>`

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<_TypesafeBuilderFilled, _TypesafeBuilderEmpty>`
//        method `build` is available on `ConfigBuilder<_TypesafeBuilderFilled, _TypesafeBuilderFilled>`

🔍 Real-World Use Cases

Web API Configuration

#[derive(Builder)]
struct ApiConfig {
    #[builder(required)]
    base_url: String,
    
    #[builder(optional)]
    use_auth: Option<bool>,
    
    #[builder(required_if = "use_auth")]
    api_key: Option<String>,
    
    #[builder(required_if = "use_auth")]
    secret: Option<String>,
    
    #[builder(optional)]
    timeout_seconds: Option<u64>,
}

Database Connection

#[derive(Builder)]
struct DatabaseConfig {
    #[builder(required)]
    host: String,
    
    #[builder(required)]
    database: String,
    
    #[builder(optional)]
    use_ssl: Option<bool>,
    
    #[builder(required_if = "use_ssl")]
    ssl_cert_path: Option<String>,
    
    #[builder(optional_if = "!use_ssl")]
    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 typesafe_builder_derive --test ui

👥 Contributors

Amazing developers who have contributed to this project:

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 ⭐!