Rust assembly generation: Static vs dynamic dispatch

pub trait Shape {
    type T;
    fn area(&self) -> Self::T;
}

pub struct Point<T> {
    x: T,
    y: T,
}

pub struct Rectangle<T> {
    top_left: Point<T>,
    bottom_right : Point<T>
}

impl<T> Shape for Rectangle<T> 
where T: std::ops::Sub<Output = T> + std::ops::Mul<Output = T> + Copy {
    type T = T;
    fn area(&self) -> T {
        let width = self.bottom_right.x - self.top_left.x;
        let height = self.top_left.y - self.bottom_right.y;

        width * height
    }
}

impl<T> Rectangle<T> {
    fn new(top_left: Point<T>, bottom_right: Point<T>) -> Self {
        Self { top_left, bottom_right}
    }
}

pub fn area_pair_static(a : impl Shape<T = f64>, b: impl Shape<T = f64>) -> (f64, f64) {
    (a.area(), b.area())
}

pub fn static_dispatch_pair(a: Rectangle<f64>, b: Rectangle<f64>) -> (f64, f64){
    area_pair_static(a,b)
}

pub fn area_pair_dynamic(a : &dyn Shape<T = f64>, b: &dyn Shape<T = f64>) -> (f64, f64) {
    (a.area(), b.area())
}

pub fn dynamic_dispatch_pair(a: Rectangle<f64>, b: Rectangle<f64>) -> (f64, f64){
    area_pair_dynamic(&a,&b)
}

Reference