Associated Type Bounds

// Define a trait `AnimalTrait` with an associated type `A`.
trait AnimalTrait {
    // Associated type for the animal's type (e.g., Cat).
    type A;

    // A method to create an instance of the animal.
    fn create() -> Self;

    // A method to get the name of the animal.
    fn name(&self) -> &str;
}

// Define a struct `Cat` that implements the `AnimalTrait` trait.
struct Cat;

impl AnimalTrait for Cat {
    type A = Cat;

    fn create() -> Self {
        Cat
    }

    fn name(&self) -> &str {
        "Cat"
    }
}

// Define a struct `Dog` that implements the `AnimalTrait` trait.
struct Dog;

impl AnimalTrait for Dog {
    type A = Dog;

    fn create() -> Self {
        Dog
    }

    fn name(&self) -> &str {
        "Dog"
    }
}

// This will look fancy a bit.
fn adopt_cat<T>(cat: T)
where
    // Here it is an 👇 Associated Type Bounds.
    T: AnimalTrait<A = Cat>,
{
    let cat_instance = T::create();
    let cat_name = cat_instance.name();

    println!("Adopted a {} named {}", cat.name(), cat_name);
}

fn main() {
    // Call the `adopt_cat` function, passing a `Cat` instance.
    adopt_cat(Cat);

    // 😱 Attempt to call the `adopt_cat` function with a `Dog` instance.
    // 👇 This will result in a compilation error.
    // adopt_cat(Dog);
    // --------- ^^^ type mismatch resolving `<Dog as AnimalTrait>::A == Cat`
}