Stilltypes
Domain-specific refined types for Rust
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 |
network |
Ipv4Addr, Ipv6Addr, DomainName, Port |
- |
geo |
Latitude, Longitude |
- |
numeric |
Percentage, UnitInterval |
- |
identifiers |
Slug |
- |
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!;
Network (IP, Domain, Port)
use ;
// IPv4 validation with semantic helpers
let ip = new?;
assert!;
assert!;
// IPv6 validation
let ipv6 = new?;
assert!;
// Port validation with IANA range classification
let port = new?;
assert!;
assert!;
// Domain name validation (RFC 1035)
let domain = new?;
assert_eq!;
Geographic Coordinates
use ;
// Latitude validates range -90 to 90 degrees
let lat = new?;
assert!;
// Longitude validates range -180 to 180 degrees
let lon = new?;
assert!;
// Convert to degrees, minutes, seconds
let = lat.to_dms;
// 37° 46' 29.64" N
Bounded Numerics
use ;
// Percentage validates range 0 to 100
let discount = new?;
let price = 100.0;
let discounted = price - discount.of; // 75.0
// Convert between representations
let probability = new?;
let as_percent = probability.to_percentage; // 75%
// Create from decimal
let half = from_decimal?; // 50%
URL Slugs
use ;
// Validate existing slug
let slug = new?;
assert_eq!;
// Convert from title
let slug = from_title?;
assert_eq!;
// Error on invalid slugs
let invalid = new;
assert!;
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()network_validation.rs- Server config validation with IP/port/domaingeo_validation.rs- Geographic coordinate validation with DMS conversiondiscount_validation.rs- Percentage and pricing calculations with numeric typesslug_validation.rs- URL slug validation and title conversion
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.