Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
use std::marker::PhantomData;
// PhantomData marks ownership and variancestructMyIterator<'a, T> {
ptr: *const T,
end: *const T,
_marker: PhantomData<&'a T>, // Tells compiler: we borrow T
}
// Without PhantomData, compiler doesn't know about the 'a lifetime
// Use marker traits to signal capabilitiestraitSendable: Send + 'static {}
// Sealed trait pattern (prevent external implementation)mod sealed {
pubtraitSealed {}
}
pubtraitMyTrait: sealed::Sealed {
fnmethod(&self);
}
// Only types we define can implement MyTraitstructMyType;
implsealed::Sealed forMyType {}
implMyTraitforMyType {
fnmethod(&self) { ... }
}
Zero-Sized Types (ZST)
// Use ZST for compile-time markers (no runtime cost)structDebugOnly;
structAlways;
structLogger<Mode = Always> {
_marker: PhantomData<Mode>,
}
implLogger<DebugOnly> {
pubfnlog(&self, msg: &str) {
#[cfg(debug_assertions)]println!("[DEBUG] {}", msg);
}
}
implLogger<Always> {
pubfnlog(&self, msg: &str) {
println!("[LOG] {}", msg);
}
}
// ZST has zero runtime cost:assert_eq!(std::mem::size_of::<Logger<DebugOnly>>(), 0);
Workflow
Step 1: Identify Domain Invariants
What can go wrong?
→ IDs mixed up? Use newtype
→ Invalid state transitions? Use type state
→ Optional fields always present? Remove Option
→ Values need validation? Validate in constructor
Step 2: Choose Type Pattern
Need to:
→ Prevent ID confusion? Newtype pattern
→ Encode state machine? Type state pattern
→ Enforce required fields? Builder with type state
→ Mark variance/ownership? PhantomData
→ Zero-cost abstraction? ZST
Step 3: Validate at Construction
// ✅ Validation at constructionimplEmail {
pubfnnew(s: &str) ->Result<Self, Error> {
validate(s)?; // Validate onceOk(Email(s.to_string()))
}
}
// Now Email is always validfnsend_email(to: Email) {
// No need to re-validate
}
Anti-Patterns
Anti-Pattern
Problem
Solution
is_valid flag
Runtime checking
Use type states
Many Options
Nullable everywhere
Redesign types
Primitive types everywhere
Type confusion
Newtype pattern
Runtime validation
Late error discovery
Constructor validation
Boolean parameters
Unclear meaning
Use enum or builder
Validation Timing
Validation Type
Best Time
Example
Range validation
Construction
Email::new() returns Result
State transitions
Type boundaries
Connection<Connected>
Reference validity
Lifetimes
&'a T
Thread safety
Send + Sync
Compiler checks
Review Checklist
When reviewing type design:
Invalid states are unrepresentable
Newtypes used for domain concepts
Validation happens at construction
Type states prevent invalid operations
No boolean blindness (use enums)
PhantomData correctly marks ownership
Builder enforces required fields
Marker traits document capabilities
ZSTs used for zero-cost abstractions
Verification Commands
# Check type sizes
cargo build --release
nm target/release/myapp | grep MyType
# Ensure ZST optimization
objdump -d target/release/myapp | grep -A 10 my_function
# Test type-level guarantees
cargo test --lib