common-stdx 0.1.15

extension for the std lib, for things i commonly reuse
Documentation
use num_traits::Num;
use num_traits::NumCast;
use std::ops::Div;

pub struct ComplexNum<T: Num + Copy> {
    real: T,
    imaginary: T,
}

pub struct ComplexPolar<T: Num + Copy> {
    radius: T,
    angle: T,
}

impl<T> ComplexNum<T>
where
    T: Copy + Clone + NumCast + Num,
{
    pub fn new(real: T, imaginary: T) -> Self {
        ComplexNum { real, imaginary }
    }

    pub fn conjugate(self) -> Self {
        ComplexNum::new(self.real, T::zero() - self.imaginary)
    }

    pub fn as_tuple(self) -> (T, T) {
        (self.real, self.imaginary)
    }

    pub fn from_polar(polar: ComplexPolar<T>) -> Option<Self> {
        let radius = polar.radius.to_f64()?;
        let angle = polar.angle.to_f64()?;

        let real_f64 = radius * angle.cos();
        let imaginary_f64 = radius * angle.sin();

        Some(ComplexNum {
            real: NumCast::from(real_f64)?,
            imaginary: NumCast::from(imaginary_f64)?,
        })
    }
    pub fn as_polar(&self) -> Option<ComplexPolar<T>> {
        let a = self.real.to_f64()?;
        let b = self.imaginary.to_f64()?;

        let radius = (a * a + b * b).sqrt();
        let angle = b.atan2(a);

        Some(ComplexPolar {
            radius: NumCast::from(radius)?,
            angle: NumCast::from(angle)?,
        })
    }
}

impl<T> std::ops::Add for ComplexNum<T>
where
    T: Num + Copy + Clone + NumCast,
{
    type Output = ComplexNum<T>;

    fn add(self, rhs: Self) -> Self::Output {
        ComplexNum::new(self.real + rhs.real, self.imaginary + rhs.imaginary)
    }
}

impl<T> std::ops::Sub for ComplexNum<T>
where
    T: Num + Copy + Clone + NumCast,
{
    type Output = ComplexNum<T>;

    fn sub(self, rhs: Self) -> Self::Output {
        ComplexNum::new(self.real - rhs.real, self.imaginary - rhs.imaginary)
    }
}

impl<T> std::ops::Mul for ComplexNum<T>
where
    T: Num + Copy + Clone + NumCast,
{
    type Output = ComplexNum<T>;

    fn mul(self, rhs: Self) -> Self::Output {
        // (a + bi)(c + di) = (ac - bd) + (ad + bc)i
        ComplexNum::new(
            self.real * rhs.real - self.imaginary * rhs.imaginary,
            self.real * rhs.imaginary + self.imaginary * rhs.real,
        )
    }
}

impl<T> std::ops::Div for ComplexNum<T>
where
    T: Num + Copy + Div<Output = T> + Clone + NumCast,
{
    type Output = ComplexNum<T>;

    fn div(self, rhs: Self) -> Self::Output {
        let denom = rhs.real * rhs.real + rhs.imaginary * rhs.imaginary;
        let numer = self * rhs.conjugate();

        ComplexNum::new(numer.real / denom, numer.imaginary / denom)
    }
}