How to manually implement the traits

This article will explain how to enable a new type for use with the float_eq!, float_ne!, assert_float_eq! and assert_float_ne! macros. If your type is a struct or tuple struct and is not generic, then you may wish to derive these traits instead, see How to derive the traits.

The float_eq! and float_ne! macros require FloatEqUlpsTol and FloatEq and may optionally use FloatEqAll. Likewise, assert_float_eq! and assert_float_ne! require FloatEqDebugUlpsDiff and AssertFloatEq and may optionally use AssertFloatEqAll.

The Point type

By way of example, we will implement the traits for this Point type:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Copy, PartialEq)]
struct Point {
    pub x: f64,
    pub y: f64,
}
}

Implementing FloatEqUlpsTol

Provide an UlpsTol representation for each of the fields:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Copy, PartialEq)]
struct PointUlps {
    pub x: UlpsTol<f64>,
    pub y: UlpsTol<f64>,
}

impl FloatEqUlpsTol for Point {
    type UlpsTol = PointUlps;
}
}

Implementing FloatEq

Requires FloatEqUlpsTol. Implementation is usually a matter of calling through to an underlying FloatEq method for each field in turn. If not, you will need to take a close look at the descriptions of the algorithms on a method by method basis:

#![allow(unused)]
fn main() {
impl FloatEq for Point {
    type Tol = Point;

    fn eq_abs(&self, other: &Self, tol: &Point) -> bool {
        self.x.eq_abs(&other.x, &tol.x) &&
        self.y.eq_abs(&other.y, &tol.y)
    }

    fn eq_rmax(&self, other: &Self, tol: &Point) -> bool {
        self.x.eq_rmax(&other.x, &tol.x) &&
        self.y.eq_rmax(&other.y, &tol.y)
    }

    fn eq_rmin(&self, other: &Self, tol: &Point) -> bool {
        self.x.eq_rmin(&other.x, &tol.x) &&
        self.y.eq_rmin(&other.y, &tol.y)
    }

    fn eq_r1st(&self, other: &Self, tol: &Point) -> bool {
        self.x.eq_r1st(&other.x, &tol.x) &&
        self.y.eq_r1st(&other.y, &tol.y)
    }

    fn eq_r2nd(&self, other: &Self, tol: &Point) -> bool {
        self.x.eq_r2nd(&other.x, &tol.x) &&
        self.y.eq_r2nd(&other.y, &tol.y)
    }

    fn eq_ulps(&self, other: &Self, tol: &UlpsTol<Point>) -> bool {
        self.x.eq_ulps(&other.x, &tol.x) &&
        self.y.eq_ulps(&other.y, &tol.y)
    }
}
}

Implementing FloatEqAll

Select a tolerance type to compare recursively with each field in your type, likely f32 or f64. Implementation is then usually a matter of calling through to an underlying FloatEqAll method for each field in turn. If not, you will need to take a close look at the descriptions of the algorithms on a method by method basis:

#![allow(unused)]
fn main() {
impl FloatEqAll for Point {
    type AllTol = f64;

    fn eq_abs_all(&self, other: &Self, tol: &f64) -> bool {
        self.x.eq_abs_all(&other.x, tol) &&
        self.y.eq_abs_all(&other.y, tol)
    }

    fn eq_rmax_all(&self, other: &Self, tol: &f64) -> bool {
        self.x.eq_rmax_all(&other.x, tol) &&
        self.y.eq_rmax_all(&other.y, tol)
    }

    fn eq_rmin_all(&self, other: &Self, tol: &f64) -> bool {
        self.x.eq_rmin_all(&other.x, tol) &&
        self.y.eq_rmin_all(&other.y, tol)
    }

    fn eq_r1st_all(&self, other: &Self, tol: &f64) -> bool {
        self.x.eq_r1st_all(&other.x, tol) &&
        self.y.eq_r1st_all(&other.y, tol)
    }

    fn eq_r2nd_all(&self, other: &Self, tol: &f64) -> bool {
        self.x.eq_r2nd_all(&other.x, tol) &&
        self.y.eq_r2nd_all(&other.y, tol)
    }

    fn eq_ulps_all(&self, other: &Self, tol: &UlpsTol<f64>) -> bool {
        self.x.eq_ulps_all(&other.x, tol) &&
        self.y.eq_ulps_all(&other.y, tol)
    }
}
}

Implementing FloatEqDebugUlpsDiff

Types should provide a DebugUlpsDiff representation for each of their fields:

#![allow(unused)]
fn main() {
#[derive(Debug, Clone, Copy, PartialEq)]
struct PointDebugUlpsDiff {
    pub x: DebugUlpsDiff<f64>,
    pub y: DebugUlpsDiff<f64>,
}

impl FloatEqDebugUlpsDiff for Point {
    type DebugUlpsDiff = PointDebugUlpsDiff;
}
}

Implementing AssertFloatEq

Requires FloatEqUlpsTol, FloatEq and FloatEqDebugUlpsDiff. Implementation is then usually a matter of simply calling through to an underlying AssertFloatEq method for each field in turn. If not, you will need to take a close look at the descriptions of the algorithms on a method by method basis:

#![allow(unused)]
fn main() {
impl AssertFloatEq for Point {
    type DebugAbsDiff = Self;
    type DebugTol = Self;

    fn debug_abs_diff(&self, other: &Self) -> Point {
        Point {
            x: self.x.debug_abs_diff(&other.x),
            y: self.y.debug_abs_diff(&other.y),
        }
    }

    fn debug_ulps_diff(&self, other: &Self) -> PointDebugUlpsDiff {
        PointDebugUlpsDiff {
            x: self.x.debug_ulps_diff(&other.x),
            y: self.y.debug_ulps_diff(&other.y),
        }
    }

    fn debug_abs_tol(
        &self,
        other: &Self,
        tol: &Point
    ) -> Point {
        Point {
            x: self.x.debug_abs_tol(&other.x, &tol.x),
            y: self.y.debug_abs_tol(&other.y, &tol.y),
        }
    }

    fn debug_rmax_tol(
        &self,
        other: &Self,
        tol: &Point
    ) -> Point {
        Point {
            x: self.x.debug_rmax_tol(&other.x, &tol.x),
            y: self.y.debug_rmax_tol(&other.y, &tol.y),
        }
    }

    fn debug_rmin_tol(
        &self,
        other: &Self,
        tol: &Point
    ) -> Point {
        Point {
            x: self.x.debug_rmin_tol(&other.x, &tol.x),
            y: self.y.debug_rmin_tol(&other.y, &tol.y),
        }
    }

    fn debug_r1st_tol(
        &self,
        other: &Self,
        tol: &Point
    ) -> Point {
        Point {
            x: self.x.debug_r1st_tol(&other.x, &tol.x),
            y: self.y.debug_r1st_tol(&other.y, &tol.y),
        }
    }

    fn debug_r2nd_tol(
        &self,
        other: &Self,
        tol: &Point
    ) -> Point {
        Point {
            x: self.x.debug_r2nd_tol(&other.x, &tol.x),
            y: self.y.debug_r2nd_tol(&other.y, &tol.y),
        }
    }

    fn debug_ulps_tol(
        &self,
        other: &Self,
        tol: &PointUlps,
    ) -> PointUlps {
        PointUlps {
            x: self.x.debug_ulps_tol(&other.x, &tol.x),
            y: self.y.debug_ulps_tol(&other.y, &tol.y),
        }
    }
}
}

Implementing AssertFloatEqAll

Requires FloatEqUlpsTol, FloatEq, FloatEqAll, FloatEqDebugUlpsDiff and AssertFloatEq. Implementation is then usually a matter of simply calling through to an underlying AssertFloatEqAll method for each field in turn. If not, you will need to take a close look at the descriptions of the algorithms on a method by method basis:

#![allow(unused)]
fn main() {
impl AssertFloatEqAll for Point {
    type AllDebugTol = Self;

    fn debug_abs_all_tol(
        &self,
        other: &Self,
        tol: &Self::AllTol
    ) -> Self::AllDebugTol {
        Point {
            x: self.x.debug_abs_all_tol(&other.x, tol),
            y: self.y.debug_abs_all_tol(&other.y, tol),
        }
    }

    fn debug_rmax_all_tol(
        &self,
        other: &Self,
        tol: &Self::AllTol
    ) -> Self::AllDebugTol {
        Point {
            x: self.x.debug_rmax_all_tol(&other.x, tol),
            y: self.y.debug_rmax_all_tol(&other.y, tol),
        }
    }

    fn debug_rmin_all_tol(
        &self,
        other: &Self,
        tol: &Self::AllTol
    ) -> Self::AllDebugTol {
        Point {
            x: self.x.debug_rmin_all_tol(&other.x, tol),
            y: self.y.debug_rmin_all_tol(&other.y, tol),
        }
    }

    fn debug_r1st_all_tol(
        &self,
        other: &Self,
        tol: &Self::AllTol
    ) -> Self::AllDebugTol {
        Point {
            x: self.x.debug_r1st_all_tol(&other.x, tol),
            y: self.y.debug_r1st_all_tol(&other.y, tol),
        }
    }

    fn debug_r2nd_all_tol(
        &self,
        other: &Self,
        tol: &Self::AllTol
    ) -> Self::AllDebugTol {
        Point {
            x: self.x.debug_r2nd_all_tol(&other.x, tol),
            y: self.y.debug_r2nd_all_tol(&other.y, tol),
        }
    }

    fn debug_ulps_all_tol(
        &self,
        other: &Self,
        tol: &UlpsTol<Self::AllTol>,
    ) -> UlpsTol<Self::AllDebugTol> {
        PointUlps {
            x: self.x.debug_ulps_all_tol(&other.x, tol),
            y: self.y.debug_ulps_all_tol(&other.y, tol),
        }
    }
}
}