Is the above snippet is an example of the implementation of trait for a generic type or implementation of a generic trait for a generic type? To understand the difference between the two ideas, some reference to use case would be helpful.
Any implementation where a type appears uncovered. impl<T> Foo for T, impl<T> Bar<T> for T, impl<T> Bar<Vec<T>> for T, and impl<T> Bar<T> for Vec<T> are considered blanket impls. However, impl<T> Bar<Vec<T>> for Vec<T> is not a blanket impl, as all instances of T which appear in this impl are covered by Vec.
In this case, the &T and &mut T are called fundamental type constructors which are uncovered by its definition:
A fundamental type constructor is a type where implementing a blanket implementation over it is a breaking change. &, &mut, Box, and Pin are fundamental.
Any time a type T is considered local, &T, &mut T, Box<T>, and Pin<T> are also considered local. Fundamental type constructors cannot cover other types. Any time the term "covered type" is used, the T in &T, &mut T, Box<T>, and Pin<T> is not considered covered.
Ignoring terminology for a moment, let's take a look at what the code does.
The first stanza declares the trait.
The second stanza implements the trait for any &T, provided T implements the trait. The implementation of aabb for &T takes a &&T as self and then calls T's aabb with a &T (one less reference nesting). It's not entirely obvious because they are relying on autoderef, but you can tell from the T::.
The third stanza is similar to the second.
If you implement the trait for YourType, the blanket implementations mean it will be implemented for &YourType, &mut YourType, &&mut &&&YourType, etc. Those just recursively call implementations with one less layer of nesting as discussed, until they eventually call your implementation.
If you had a
fn foo<T: Bounded>(t: T) { ... }
you could pass it a YourType or &YourType, etc.
I'd say the important part is to understand what types the implementations apply to.
The trait Bounded isn't generic as it has no type parameter. The types &T and &mut T are generic because they have a type parameter T.
Thus impl<T: Bounded> Bounded for &T and impl<T: Bounded> Bounded for &mut T are implementations of the trait Bounded for a generic type (&T and &mut T in this example).
I would say they are implementations "of a trait for a generic type".
It's unusual to implement a type, which is implemented for T, also for &T and &mut. I'm curious where this example comes from and what's the context.
It's not at all unusual, it's quite common (and idiomatic) for traits that mostly perform read-only operations. Std itself does this for Display/Debug, for example. Serde's Serialize is transitive, too. Implementing transitively for mutable references only is common, too – std's Read and Write work like this, for example.
Oh, I wasn't aware of that. When exactly does it make sense to provide such implementations? I would assume when you sometimes pass an owned value and sometimes a reference to that value, and you want the trait to be fulfilled in both cases? So it's some sort of ergonomical trick?
It makes sense when the trait only uses &self, or when it uses &mut self but you have interior mutability (like File, via your OS). The latter is more than ergonomic as maybe you can't provide a &mut File.
It's ergonomic for arguments, but more than ergonomic for owning containers. Consider what implementation makes Vec<T>: Debug, say.
I remember the File case from when I started getting into Rust. However, it's different than the generic trait impls above: The impl Write for &File is specific to a particular type (File) and not generic, i.e. there is no impl<T: Write> Write for &T:
use std::io::Write;
fn write<T: Write>(_arg: T) {}
fn main() {
let mut s: Vec<u8> = Vec::new();
write(&mut s); // works
//write(&s); // fails
write(s); // works
}
So I guess it makes sense to impl<T: Trait> Trait for &T if all methods take a &self as receiver, and impl<T: Trait> for &mut T if all methods take a &self or &mut self (but never self) as receiver.