#[macro_export]
macro_rules! impl_approx_eq_wrapper {
(@emit_cmp abs, $lhs:ident, $rhs:ident, $tol:ident, [$($field:tt),+]) => {
true $( && $crate::algebra::ApproxEqAbs::approx_eq_abs_tol(&$lhs.$field, &$rhs.$field, $tol) )+
};
(@emit_cmp rel, $lhs:ident, $rhs:ident, $tol:ident, [$($field:tt),+]) => {
true $( && $crate::algebra::ApproxEqRel::approx_eq_rel_tol(&$lhs.$field, &$rhs.$field, $tol) )+
};
(@impl_trait
[$($impl_generics:tt)*],
impl: $outer:ty,
item: $item:ident,
bounds: [$($bounds:tt)*],
trait: $trait_name:ident,
bound_trait: $bound_trait:ident,
default_from_trait: $default_from_trait:ident,
default_const: $default_const:ident,
method: $method_name:ident,
body: |$lhs:ident, $rhs:ident, $tol:ident| $expr:expr
) => {
impl<$($impl_generics)*> $crate::algebra::$trait_name for $outer
where
$item: Copy
+ $crate::algebra::$bound_trait<Tolerance = $item>
$($bounds)*
{
type Tolerance = $item;
const $default_const: Self::Tolerance =
<$item as $crate::algebra::$default_from_trait>::$default_const;
#[inline]
fn $method_name(&self, other: &Self, tol: Self::Tolerance) -> bool {
let $lhs = self;
let $rhs = other;
let $tol = tol;
$expr
}
}
};
(@impl_fields
[$($impl_generics:tt)*],
impl: $outer:ty,
item: $item:ident,
bounds: [$($bounds:tt)*],
fields: [$($field:tt),+ $(,)?]
) => {
impl<$($impl_generics)*> $outer
where
$item: Copy
+ $crate::algebra::ApproxEqAbs<Tolerance = $item>
$($bounds)*
{
#[inline]
pub fn approx_eq_abs_tol(&self, other: &Self, tol: $item) -> bool {
$crate::impl_approx_eq_wrapper!(
@emit_cmp abs,
self,
other,
tol,
[$($field),+]
)
}
#[inline]
pub fn approx_eq_abs(&self, other: &Self) -> bool {
self.approx_eq_abs_tol(other, <$item as $crate::algebra::ApproxEqAbs>::DEFAULT_TOLERANCE_ABS)
}
}
impl<$($impl_generics)*> $outer
where
$item: Copy
+ $crate::algebra::ApproxEqRel<Tolerance = $item>
$($bounds)*
{
#[inline]
pub fn approx_eq_rel_tol(&self, other: &Self, tol: $item) -> bool {
$crate::impl_approx_eq_wrapper!(
@emit_cmp rel,
self,
other,
tol,
[$($field),+]
)
}
#[inline]
pub fn approx_eq_rel(&self, other: &Self) -> bool {
self.approx_eq_rel_tol(other, <$item as $crate::algebra::ApproxEqRel>::DEFAULT_TOLERANCE_REL)
}
}
$crate::impl_approx_eq_wrapper!(
@impl_trait
[$($impl_generics)*],
impl: $outer,
item: $item,
bounds: [$($bounds)*],
trait: ApproxEqAbs,
bound_trait: ApproxEqAbs,
default_from_trait: ApproxEqAbs,
default_const: DEFAULT_TOLERANCE_ABS,
method: approx_eq_abs_tol,
body: |lhs, rhs, tol| $crate::impl_approx_eq_wrapper!(
@emit_cmp abs,
lhs,
rhs,
tol,
[$($field),+]
)
);
$crate::impl_approx_eq_wrapper!(
@impl_trait
[$($impl_generics)*],
impl: $outer,
item: $item,
bounds: [$($bounds)*],
trait: ApproxEqRel,
bound_trait: ApproxEqRel,
default_from_trait: ApproxEqRel,
default_const: DEFAULT_TOLERANCE_REL,
method: approx_eq_rel_tol,
body: |lhs, rhs, tol| $crate::impl_approx_eq_wrapper!(
@emit_cmp rel,
lhs,
rhs,
tol,
[$($field),+]
)
);
};
(@impl_callback
[$($impl_generics:tt)*],
impl: $outer:ty,
item: $item:ident,
bounds: [$($bounds:tt)*],
compare_abs: |$abs_lhs:ident, $abs_rhs:ident, $abs_tol:ident| $abs_expr:expr,
compare_rel: |$rel_lhs:ident, $rel_rhs:ident, $rel_tol:ident| $rel_expr:expr
) => {
impl<$($impl_generics)*> $outer
where
$item: Copy
+ $crate::algebra::ApproxEqAbs<Tolerance = $item>
$($bounds)*
{
#[inline]
pub fn approx_eq_abs_tol(&self, other: &Self, tol: $item) -> bool {
let $abs_lhs = self;
let $abs_rhs = other;
let $abs_tol = tol;
$abs_expr
}
#[inline]
pub fn approx_eq_abs(&self, other: &Self) -> bool {
self.approx_eq_abs_tol(other, <$item as $crate::algebra::ApproxEqAbs>::DEFAULT_TOLERANCE_ABS)
}
}
impl<$($impl_generics)*> $outer
where
$item: Copy
+ $crate::algebra::ApproxEqRel<Tolerance = $item>
$($bounds)*
{
#[inline]
pub fn approx_eq_rel_tol(&self, other: &Self, tol: $item) -> bool {
let $rel_lhs = self;
let $rel_rhs = other;
let $rel_tol = tol;
$rel_expr
}
#[inline]
pub fn approx_eq_rel(&self, other: &Self) -> bool {
self.approx_eq_rel_tol(other, <$item as $crate::algebra::ApproxEqRel>::DEFAULT_TOLERANCE_REL)
}
}
$crate::impl_approx_eq_wrapper!(
@impl_trait
[$($impl_generics)*],
impl: $outer,
item: $item,
bounds: [$($bounds)*],
trait: ApproxEqAbs,
bound_trait: ApproxEqAbs,
default_from_trait: ApproxEqAbs,
default_const: DEFAULT_TOLERANCE_ABS,
method: approx_eq_abs_tol,
body: |$abs_lhs, $abs_rhs, $abs_tol| $abs_expr
);
$crate::impl_approx_eq_wrapper!(
@impl_trait
[$($impl_generics)*],
impl: $outer,
item: $item,
bounds: [$($bounds)*],
trait: ApproxEqRel,
bound_trait: ApproxEqRel,
default_from_trait: ApproxEqRel,
default_const: DEFAULT_TOLERANCE_REL,
method: approx_eq_rel_tol,
body: |$rel_lhs, $rel_rhs, $rel_tol| $rel_expr
);
};
(
[$($impl_generics:tt)*],
impl: $outer:ty,
item: $item:ident,
extra_bounds: [$($extra_bounds:tt)+],
field: $field:tt
$(,)?
) => {
$crate::impl_approx_eq_wrapper!(
@impl_fields
[$($impl_generics)*],
impl: $outer,
item: $item,
bounds: [+ $($extra_bounds)+],
fields: [$field]
);
};
(
[$($impl_generics:tt)*],
impl: $outer:ty,
item: $item:ident,
field: $field:tt
$(,)?
) => {
$crate::impl_approx_eq_wrapper!(
@impl_fields
[$($impl_generics)*],
impl: $outer,
item: $item,
bounds: [],
fields: [$field]
);
};
(
[$($impl_generics:tt)*],
impl: $outer:ty,
item: $item:ident,
extra_bounds: [$($extra_bounds:tt)+],
fields: [$($field:tt),+ $(,)?]
$(,)?
) => {
$crate::impl_approx_eq_wrapper!(
@impl_fields
[$($impl_generics)*],
impl: $outer,
item: $item,
bounds: [+ $($extra_bounds)+],
fields: [$($field),+]
);
};
(
[$($impl_generics:tt)*],
impl: $outer:ty,
item: $item:ident,
fields: [$($field:tt),+ $(,)?]
$(,)?
) => {
$crate::impl_approx_eq_wrapper!(
@impl_fields
[$($impl_generics)*],
impl: $outer,
item: $item,
bounds: [],
fields: [$($field),+]
);
};
(
[$($impl_generics:tt)*],
impl: $outer:ty,
item: $item:ident,
extra_bounds: [$($extra_bounds:tt)+]
$(,)?
) => {
$crate::impl_approx_eq_wrapper!(
[$($impl_generics)*],
impl: $outer,
item: $item,
extra_bounds: [$($extra_bounds)+],
field: 0
);
};
(
[$($impl_generics:tt)*],
impl: $outer:ty,
item: $item:ident
$(,)?
) => {
$crate::impl_approx_eq_wrapper!(
[$($impl_generics)*],
impl: $outer,
item: $item,
field: 0
);
};
(
[$($impl_generics:tt)*],
impl: $outer:ty,
item: $item:ident,
extra_bounds: [$($extra_bounds:tt)+],
compare_abs: |$abs_lhs:ident, $abs_rhs:ident, $abs_tol:ident| $abs_expr:expr,
compare_rel: |$rel_lhs:ident, $rel_rhs:ident, $rel_tol:ident| $rel_expr:expr
$(,)?
) => {
$crate::impl_approx_eq_wrapper!(
@impl_callback
[$($impl_generics)*],
impl: $outer,
item: $item,
bounds: [+ $($extra_bounds)+],
compare_abs: |$abs_lhs, $abs_rhs, $abs_tol| $abs_expr,
compare_rel: |$rel_lhs, $rel_rhs, $rel_tol| $rel_expr
);
};
(
[$($impl_generics:tt)*],
impl: $outer:ty,
item: $item:ident,
compare_abs: |$abs_lhs:ident, $abs_rhs:ident, $abs_tol:ident| $abs_expr:expr,
compare_rel: |$rel_lhs:ident, $rel_rhs:ident, $rel_tol:ident| $rel_expr:expr
$(,)?
) => {
$crate::impl_approx_eq_wrapper!(
@impl_callback
[$($impl_generics)*],
impl: $outer,
item: $item,
bounds: [],
compare_abs: |$abs_lhs, $abs_rhs, $abs_tol| $abs_expr,
compare_rel: |$rel_lhs, $rel_rhs, $rel_tol| $rel_expr
);
};
}