An open API service indexing awesome lists of open source software.

https://github.com/tomoikey/typesafe_builder

🚀 The Ultimate Builder Pattern Implementation Powered by Rust's Type System. Type safety is not a luxury, it's a necessity.
https://github.com/tomoikey/typesafe_builder

builder crate crates crates-io library patterns rust rust-lang typesafe

Last synced: 23 days ago
JSON representation

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

Awesome Lists containing this project

README

          

# TypeSafe Builder


crates.io
downloads
license
rustc



GitHub stars


GitHub forks

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**.

```rust
// ❌ 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
- **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`

### Performance Characteristics
- **Zero Runtime Cost** - All validation completed at compile time

### Safety Guarantees
- **No Panic** - Complete elimination of runtime panics

## Quick Start

```toml
[dependencies]
typesafe_builder = "*.*.*" # Replace with the actual version
```

```rust
use typesafe_builder::*;

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

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

## Advanced Features

### 1. Conditional Required Fields

```rust
use typesafe_builder::*;

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

// ✅ 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

```rust
use typesafe_builder::*;

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

// ✅ 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

```rust
use typesafe_builder::*;

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

// Secret is required if using auth OR HTTPS
#[builder(required_if = "use_auth || use_https")]
secret: Option,

// Certificate is required only when using both auth AND HTTPS
#[builder(required_if = "use_auth && use_https")]
certificate: Option,

// Warning is required when using neither auth NOR HTTPS
#[builder(required_if = "!use_auth && !use_https")]
insecure_warning: Option,

// Complex condition: Token required when (auth OR HTTPS) AND (no API key)
#[builder(required_if = "(use_auth || use_https) && !api_key")]
fallback_token: Option,
}

// ✅ 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. Default Values

TypeSafe Builder supports two ways to specify default values:

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

```rust
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,

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

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

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

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

#### Custom Default Expressions

```rust
use typesafe_builder::*;

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

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

#[builder(default = "vec![\"GET\".to_string(), \"POST\".to_string()]")]
allowed_methods: Vec,

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

#[builder(required)]
service_name: String,

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

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

// ✅ Override some defaults
let config2 = ServerConfigBuilder::new()
.with_service_name("my-api".to_string())
.with_host("0.0.0.0".to_string())
.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(\"APP_NAME\").unwrap_or_else(|_| \"default-app\".to_string())")]
app_name: String,

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

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

#### Mixed Default Types

```rust
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,

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

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

```rust
use typesafe_builder::*;

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

// Warning message required when NOT using SSL
#[builder(required_if = "!use_ssl")]
warning_message: Option,
}

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

### 6. Into Conversion Support

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

```rust
use typesafe_builder::*;

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

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

// ✅ 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()
.with_name("Bob".to_string())
.build();
```

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

### 7. Custom Builder Name

```rust
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

```rust
#[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

```rust
#[derive(Builder)]
struct Config {
#[builder(optional)]
feature: Option,
#[builder(required_if = "feature")]
config: Option,
}

// ❌ 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

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

#[builder(optional)]
use_auth: Option,

#[builder(required_if = "use_auth")]
api_key: Option,

#[builder(required_if = "use_auth")]
secret: Option,

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

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

### Database Connection

```rust
#[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,

#[builder(required_if = "use_ssl")]
ssl_cert_path: Option,

#[builder(optional_if = "!use_ssl")]
allow_insecure: Option,
}
```

## Contributing

We welcome contributions to TypeSafe Builder!

### Development Environment Setup

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

### Running Tests

```bash
# 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:




tomoikey


tomoikey


Creator & Maintainer




ramsyana


ramsyana


Contributor




You?


Your Name Here


Next Contributor


*Want to see your name here? [Contribute now](https://github.com/tomoikey/typesafe_builder/blob/main/CONTRIBUTING.md) and join our amazing community!*

[![Contributors](https://contrib.rocks/image?repo=tomoikey/typesafe_builder)](https://github.com/tomoikey/typesafe_builder/graphs/contributors)

## License

MIT License - see the [LICENSE](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.