Advanced Blanket Implementations
A blanket implementation is a generic impl block that implements a trait for an entire class of types matching a trait bound—such as impl<T: Display> ToString for T or impl<I: Iterator> IteratorExt for I. Advanced blanket implementations power extension traits, reference forwarding, and disjoint family dispatch while navigating Rust's trait coherence and overlap rules.
Pattern 1: The Extension Trait Pattern (IteratorExt, ReadExt)
Because the orphan rule forbids adding inherent methods to a type or trait defined in an upstream crate, libraries define a new local trait whose supertrait is the upstream trait (pub trait SliceExt<T>: AsRef<[T]>) and provide a universal blanket implementation (impl<S: AsRef<[T]>, T> SliceExt<T> for S {}):
pub trait IteratorStatsExt: Iterator {
fn count_and_last(mut self) -> (usize, Option<Self::Item>)
where
Self: Sized,
{
let mut count = 0;
let mut last = None;
for item in &mut self {
count += 1;
last = Some(item);
}
(count, last)
}
}
// Blanket implementation attaches `.count_and_last()` to EVERY `Iterator`:
impl<I: Iterator + ?Sized> IteratorStatsExt for I {}
fn main() {
let stats = (10..=15).filter(|n| n % 2 == 0).count_and_last();
println!("even count and last element: {:?}", stats);
}
even count and last element: (3, Some(14))
Pattern 2: Reference and Smart-Pointer Forwarding Blanket Impls
When a trait is implemented for T, a library should also implement that trait for &T, &mut T, and Box<T> (where T: ?Sized) so generic functions accepting impl MyTrait can accept borrowed references or boxed trait objects (Box<dyn MyTrait>) directly:
trait MetricSink {
fn record(&mut self, name: &str, value: u64);
}
// Forwarding blanket impl for any `&mut S` where `S: MetricSink + ?Sized`:
impl<S: MetricSink + ?Sized> MetricSink for &mut S {
fn record(&mut self, name: &str, value: u64) {
(**self).record(name, value);
}
}
// Forwarding blanket impl for `Box<S>` where `S: MetricSink + ?Sized`:
impl<S: MetricSink + ?Sized> MetricSink for Box<S> {
fn record(&mut self, name: &str, value: u64) {
(**self).record(name, value);
}
}
struct VecSink(Vec<(String, u64)>);
impl MetricSink for VecSink {
fn record(&mut self, name: &str, value: u64) {
self.0.push((name.to_string(), value));
}
}
fn emit_startup_metrics(mut sink: impl MetricSink) {
sink.record("boot_ms", 42);
sink.record("workers", 8);
}
fn main() {
let mut sink = VecSink(Vec::new());
// Pass `&mut VecSink` by value; satisfies `impl MetricSink` via blanket impl:
emit_startup_metrics(&mut sink);
emit_startup_metrics(&mut sink);
println!("recorded {} metrics: {:?}", sink.0.len(), sink.0);
}
recorded 4 metrics: [("boot_ms", 42), ("workers", 8), ("boot_ms", 42), ("workers", 8)]
Navigating Overlapping Blanket Implementation Errors (E0119)
In stable Rust, you cannot write two blanket implementations for the same target type parameter impl<T: TraitA> Target for T and impl<T: TraitB> Target for T (E0119: conflicting implementations of trait), even if no type currently implements both TraitA and TraitB—because a downstream crate or future release could implement both traits for the same type:
// ❌ does not compile
trait Summary {
fn summarize(&self) -> String;
}
impl<T: std::fmt::Display> Summary for T {
fn summarize(&self) -> String {
format!("display: {}", self)
}
}
impl<T: std::fmt::Debug> Summary for T {
fn summarize(&self) -> String {
format!("debug: {:?}", self)
}
}
fn main() {}
error[E0119]: conflicting implementations of trait `Summary`
--> src/main.rs:12:1
|
6 | impl<T: std::fmt::Display> Summary for T {
| ---------------------------------------- first implementation here
...
12 | impl<T: std::fmt::Debug> Summary for T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
Resolving Conflicting Blanket Impls with Disjoint Associated Marker Types
By adding a marker parameter trait Summary<Mode> (or routing through an associated type type Mode; on a sealed dispatch trait), the two blanket implementations become impl<T: Display> Summary<DisplayMode> for T and impl<T: Debug> Summary<DebugMode> for T, which have distinct trait headers and no longer overlap.