Stilltypes
Domain-specific refined types for the Stillwater ecosystem
Stilltypes provides production-ready domain predicates and refined types that integrate seamlessly with stillwater. Validate emails, URLs, phone numbers, and more with errors that accumulate and types that prove validity.
Quick Start
use *;
// Types validate on construction
let email = new?;
let url = new?;
// Invalid values fail with helpful errors
let bad = new;
assert!;
println!;
// invalid email address: invalid format, expected local@domain (example: user@example.com)
Features
Enable only what you need:
[]
= { = "0.1", = false, = ["email", "url"] }
| Feature | Types | Dependencies |
|---|---|---|
email (default) |
Email |
email_address |
url (default) |
Url, HttpUrl, SecureUrl |
url |
uuid |
Uuid, UuidV4, UuidV7 |
uuid |
phone |
PhoneNumber |
phonenumber |
financial |
Iban, CreditCardNumber |
iban_validate, creditcard |
serde |
Serialize/Deserialize for all types | - |
full |
All of the above | - |
Error Accumulation
Collect all validation errors at once using stillwater's Validation:
use *;
use Validation;
match validate_form
JSON Validation
With the serde feature, types validate during deserialization:
use *;
use Deserialize;
// Invalid JSON fails to deserialize
let result: = from_str;
Available Domain Types
Email (RFC 5321)
use Email;
let email = new?;
assert_eq!;
// Plus addressing works
let plus = new?;
URL (RFC 3986)
use ;
// Any valid URL
let any_url = new?;
// HTTP or HTTPS only
let http = new?;
// HTTPS only (secure)
let secure = new?;
let insecure = new;
assert!; // HTTP rejected
UUID
use ;
// Any valid UUID
let any = new?;
// Version-specific
let v4 = new?;
let v7 = new?;
// Convert to uuid::Uuid
let uuid_impl = v4.to_uuid;
assert_eq!;
Phone Numbers (E.164)
use ;
let phone = new?;
// Normalize to E.164 for storage
assert_eq!;
// Get country code
assert_eq!;
Financial
use ;
// IBAN validation
let iban = new?;
assert_eq!;
assert_eq!; // For display
// Credit card validation (Luhn algorithm)
let card = new?;
assert_eq!; // For display
assert_eq!;
When to Use Stilltypes
Use Stilltypes when:
- Validating forms with multiple fields (accumulate all errors)
- Building APIs that need comprehensive input validation
- You want type-level guarantees throughout your codebase
- Working with the Stillwater ecosystem
Skip Stilltypes if:
- Validating a single field in a simple script
- Your domain already has validation (e.g., ORM validates emails)
- You only need one domain type (just copy the predicate)
Philosophy
Stilltypes follows the Stillwater philosophy:
- Pragmatism Over Purity - No unnecessary abstractions; just predicates
- Parse, Don't Validate - Domain types encode invariants in the type
- Composition Over Complexity - Uses stillwater's
And,Or,Not - Errors Should Tell Stories - Rich context for user-facing messages
Examples
See the examples/ directory for complete working examples:
form_validation.rs- Error accumulation withValidation::all()api_handler.rs- Effect composition withfrom_validation()
Run with:
The Stillwater Ecosystem
| Library | Purpose |
|---|---|
| stillwater | Effect composition and validation core |
| stilltypes | Domain-specific refined types |
| mindset | Zero-cost state machines |
| premortem | Configuration validation |
| postmortem | JSON validation with path tracking |
License
Licensed under the MIT license. See LICENSE for details.