Skip to content

Releases: welf/type-state-builder

Release v0.5.0

12 Dec 21:09

Choose a tag to compare

Added

  • Const builder support with #[builder(const)] attribute
    • All builder methods (builder(), setters, build()) generated as const fn
    • Enables compile-time constant construction for embedded systems, static configuration, etc.
    • Closure converters automatically transformed to const fn helpers
    • Uses struct reconstruction pattern (Self { field, ..self }) for const compatibility

Validation

  • Require explicit defaults for optional fields when using const builders (Default::default() is not const)
  • Disallow impl_into attribute with const builders (trait bounds not supported in const fn)
  • Skip Default trait implementation for const builders

v0.4.1

12 Dec 00:34

Choose a tag to compare

What's New

no_std Support

TypeStateBuilder now generates code compatible with no_std environments. The generated code uses core:: types instead of std:: types:

  • core::option::Option
  • core::marker::PhantomData
  • core::fmt::Debug
  • core::default::Default

No feature flags required.

Documentation Improvements

  • Added Design Philosophy section explaining the rationale behind actionable error messages
  • Updated lib.rs documentation to complement README

Other

  • Downgraded proptest dev dependency to 1.4.0 to maintain MSRV compatibility (Rust 1.70.0)

Release v0.3.1

17 Aug 05:40

Choose a tag to compare

Fixed

  • Documentation example in generated builder method now uses ignore attribute to prevent doctest execution conflicts

Release v0.3.0

01 Aug 17:19

Choose a tag to compare

Added

  • Custom Converter Attribute: New converter attribute for advanced field transformations using closures
    • #[builder(converter = |value: InputType| expression)] for custom conversion logic
    • Support for complex transformations beyond simple Into conversions
    • Works with any valid Rust expression or closure
    • Examples:
      #[builder(converter = |s: &str| s.to_uppercase())]
      name: String,
      #[builder(converter = |items: Vec<&str>| items.iter().map(|s| s.to_string()).collect())]
      tags: Vec<String>,
    • Comprehensive validation prevents conflicts with impl_into and skip_setter attributes
    • Zero runtime overhead - all conversions happen at compile time

Changed

  • Error message format improved to follow Rust's standard diagnostic format with structured error/note/help components
  • All validation error messages now provide clearer, more actionable guidance

Improved

  • Developer Experience: More flexible field transformation options beyond basic Into conversions
  • Documentation: Comprehensive examples for converter usage patterns and best practices
  • Testing: Added extensive test coverage for converter functionality with edge cases

Fixed

  • UI test expectations updated for improved error messages
  • More validation tests for attribute conflicts and invalid combinations

Migration Guide

The converter attribute is a new optional feature that doesn't affect existing code. All existing
#[derive(TypeStateBuilder)] usage continues to work exactly as before.
New converter functionality:

#[derive(TypeStateBuilder)]
struct Config {
    // New: Custom converter for complex transformations
    #[builder(converter = |path: &str| PathBuf::from(path).canonicalize().unwrap())]
    config_path: PathBuf,
    // Existing functionality unchanged
    #[builder(required)]
    name: String,
    #[builder(impl_into, default = "description".to_string()")]
    description: String,
}

Release v0.2.0: Ergonomic Conversions with impl_into

28 Jul 14:05

Choose a tag to compare

🎯 What's New

Ergonomic Conversions with impl_into

The headline feature of this release is the new impl_into attribute system that allows setter methods to accept impl Into<FieldType> parameters instead of requiring the exact field type. This eliminates the need for manual .to_string() calls and other common conversions.

Before v0.2.0:

let user = User::builder()
    .name("Alice".to_string())           // Manual conversion required
    .email("alice@example.com".to_string()) // Manual conversion required
    .build();

With v0.2.0:

#[derive(TypeStateBuilder)]
#[builder(impl_into)]  // Enable ergonomic conversions
struct User {
    #[builder(required)]
    name: String,
    #[builder(required)]
    email: String,
}

let user = User::builder()
    .name("Alice")              // &str automatically converts to String
    .email("alice@example.com") // &str automatically converts to String
    .build();

✨ Key Features

Flexible Configuration Options

  • Struct-level: Apply #[builder(impl_into)] to enable for all setters
  • Field-level: Use #[builder(impl_into)] or #[builder(impl_into = false)] for fine-grained control
  • Smart precedence: Field-level settings override struct-level defaults
#[derive(TypeStateBuilder)]
#[builder(impl_into)]  // Default for all fields
struct Document {
    #[builder(required)]
    title: String,                       // Inherits: accepts &str, String, etc.
    #[builder(required, impl_into = false)]
    content: String,                     // Override: requires String directly
    #[builder(impl_into = true)]
    category: Option<String>,            // Explicit: accepts impl Into<String>
}

Zero Runtime Cost

All conversions happen at compile time with no performance overhead. The generated code is as efficient as if you wrote the conversions manually.

Type Safety Guaranteed

Only types that implement Into<FieldType> are accepted, maintaining Rust's compile-time safety guarantees.

Common Use Cases Supported

  • String fields: Accept &str, String, Cow<str>, and more
  • Path fields: Accept &str, &Path, String, PathBuf
  • Collection fields: Accept arrays, slices, iterators where applicable
  • Custom types: Any type implementing Into<T> works automatically

🛡️ Safety & Validation

  • Conflict detection: Prevents invalid combinations like impl_into with skip_setter
  • Clear error messages: Descriptive compile-time errors guide you to correct usage
  • Comprehensive validation: All attribute combinations are validated at compile time

📚 Enhanced Documentation

  • Complete examples: Real-world usage patterns and best practices
  • Working doctests: All documentation examples are tested and guaranteed to work
  • Migration guide: Easy upgrade path from previous versions

🧪 Robust Testing

This release includes 341+ comprehensive tests covering:

  • Unit tests for all new functionality
  • Integration tests for real-world scenarios
  • UI tests for error message validation
  • Doctest coverage for all examples

🔄 Backward Compatibility

This is a fully backward-compatible release. All existing code continues to work without any changes. The impl_into attribute is completely opt-in.

📊 What This Means For You

More Ergonomic APIs

// Before: Verbose and repetitive

let config = ServerConfig::builder()
    .host("localhost".to_string())
    .database_url("postgresql://...".to_string())
    .log_file("/var/log/app.log".to_string())
    .build();

// After: Clean and natural

#[derive(TypeStateBuilder)]
#[builder(impl_into)]
struct ServerConfig { /* ... */ }

let config = ServerConfig::builder()
    .host("localhost")
    .database_url("postgresql://...")
    .log_file("/var/log/app.log")
    .build();

Better Developer Experience

  • Less boilerplate code
  • More readable builder chains
  • Fewer manual type conversions
  • Natural API feel

Maintained Safety

  • Same compile-time guarantees
  • No runtime performance cost
  • Type safety preserved
  • Clear error messages

🚀 Getting Started

Update your Cargo.toml:

[dependencies]
type-state-builder = "0.2.0"

Add the attribute to your structs:

use type_state_builder::TypeStateBuilder;
#[derive(TypeStateBuilder)]
#[builder(impl_into)]  // Enable ergonomic conversions
struct YourStruct {
    // Your fields here
}

Full Changelog: v0.1.2...v0.2.0

v0.1.2 - Improved Type Names

27 Jul 02:06

Choose a tag to compare

Type-State Builder v0.1.2 - Improved Type Names 🏗️

This release significantly improves the readability of generated builder type names by converting snake_case field names to PascalCase in type names.

🎯 What's New

Enhanced Type Name Readability

  • Generated builder type names now use PascalCase for field names instead of preserving underscores
  • Error messages are now much clearer and follow Rust type naming conventions

📝 Before vs After

Before (0.1.1):

// Hard to read type names in error messages
LanguageConfigBuilder_HasLanguage_id_MissingFqn_separator

After (0.1.2):

// Clean, readable type names
LanguageConfigBuilder_HasLanguageId_MissingFqnSeparator

🔧 Example

#[derive(TypeStateBuilder)]
pub struct LanguageConfig {
    #[builder(required)]
    pub language_id: String,

    #[builder(required)]
    pub fqn_separator: String,
}

// Generated types are now much more readable:
// - LanguageConfigBuilder_MissingLanguageId_MissingFqnSeparator
// - LanguageConfigBuilder_HasLanguageId_MissingFqnSeparator
// - LanguageConfigBuilder_HasLanguageId_HasFqnSeparator

## 🛠️ Technical Details

- Implemented automatic snake_case to PascalCase conversion for field names in type generation
- Improved developer experience with clearer error messages
- All existing functionality remains unchanged
- Comprehensive test coverage for the new naming conventions

## 📦 Installation

```toml
[dependencies]
type-state-builder = "0.1.2"

Full Changelog: v0.1.1...v0.1.2

v0.1.1 - Fix builder visibility issue

27 Jul 01:27

Choose a tag to compare

🔧 Bug Fix Release: Visibility Inheritance

This patch release fixes a critical issue with builder visibility that prevented cross-module usage of the type-state builder pattern.

🐛 Fixed

  • Visibility inheritance: Generated builder types now correctly inherit the visibility of the original struct
    • Public structs generate public builders for cross-module usage
    • Private structs generate private builders to respect Rust privacy rules
    • All visibility levels supported: pub, pub(crate), pub(super), pub(in path), and private
    • Fixes compilation errors when using builders across module boundaries

v0.1.0 - Initial Release

26 Jul 23:53

Choose a tag to compare

Initial release of TypeStateBuilder - a derive macro for compile-time safe builder patterns in Rust.

Features

  • Initial implementation of the type-state builder pattern derive macro
  • Support for required and optional fields with compile-time validation
  • Custom setter names and prefixes for flexible API design
  • Custom build method names for enhanced usability
  • Comprehensive generic type support including lifetimes and where clauses
  • Skip setter functionality for auto-generated fields
  • Custom default values for optional fields
  • Zero runtime overhead with compile-time state machine validation
  • Automatic builder pattern selection (type-state vs regular) based on field requirements
  • Extensive test coverage including UI tests for error messages
  • Complete documentation with examples and usage patterns

Installation

Add this to your Cargo.toml:

[dependencies]
type-state-builder = "0.1.0"

See the https://docs.rs/type-state-builder for usage examples.