Advanced Generics and Type-Level Programming

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.