a blanket implementation
Sometimes you want a behaviour to apply not to one type, but to every type that already has some other property. For example: any type you can print with Display, you can also turn into a String with to_string. You would not want to write that conversion separately for i32, for f64, for your own structs, and for every type anyone ever defines. A blanket implementation lets you write it once, for all types at once, by implementing a trait for every type that satisfies a given bound.
It is an impl block whose target is a generic type parameter constrained by a where clause, rather than a single concrete type. The standard library's real example is impl<T: Display> ToString for T { fn to_string(&self) -> String { ... } }. Read it literally: 'for every type T that implements Display, here is an implementation of ToString'. The moment a type implements Display, it automatically gets to_string for free, with no extra code — that is why 5.to_string(), 3.14.to_string(), and your_struct.to_string() all work the instant the type is Display. The impl is written against the bound, so it covers an open-ended, unbounded set of types, including ones that do not exist yet. You can write your own: impl<T: MyTrait> MyOtherTrait for T { ... } grants MyOtherTrait to everything that has MyTrait.
Why this matters: blanket impls are how Rust gives whole families of types a capability in one stroke, and they are everywhere in the standard library (From/Into pairs, ToString, many iterator adapters). The honest caveat is that they interact tightly with coherence: because a blanket impl covers so many types, the compiler must guarantee no two impls can ever overlap for the same type, so you cannot freely write two blanket impls whose bounds a single type could both satisfy, and the orphan rule limits where blanket impls may live. The payoff is large, but blanket impls are also the feature most likely to collide with the coherence rules — the next entry.
// Real std blanket impl (simplified): // impl<T: Display> ToString for T { ... } use std::fmt::Display; trait Greet { fn greet(&self) -> String; } // One impl covers EVERY Display type at once: impl<T: Display> Greet for T { fn greet(&self) -> String { format!("hello, {self}") } } println!("{}", 42.greet()); // "hello, 42" println!("{}", "ada".greet()); // "hello, ada"
One impl, written against a bound, grants the trait to an open-ended set of types — every present and future type that meets the bound.
Blanket impls are powerful but constrained by coherence: because they cover so many types, the compiler forbids any overlap, so you cannot have two blanket impls a single type could both match. They are the feature most likely to hit the orphan/coherence rules.