fmt_cmp/traits/fmt_eq.rs
1use std::borrow::Borrow;
2use std::convert::Infallible;
3use std::fmt::Display;
4use std::ops::Deref;
5use std::pin::Pin;
6
7/// A marker trait for types whose equivalence relation is the same as equivalence between its
8/// `Display` representation.
9///
10/// When `T` implements `FmtEq`, the following property must be upheld for all `a: T` and `b: T`:
11///
12/// ```
13/// # let (a, b) = ("", "");
14/// assert_eq!(a == b, *format!("{}", a) == *format!("{}", b));
15/// ```
16///
17/// In other words (assuming that no ill-defined specialization is involved):
18///
19/// ```text
20/// a == b <-> a.to_string() == b.to_string()
21/// ```
22///
23/// ## Corollaries
24///
25/// From `str: Eq` and the above property, it follows that `T` satisfies [`Eq`](std::cmp::Eq)
26/// trait's contract, i.e., reflexivity, symmetricity and transitivity of `==` operator.
27///
28/// ## Examples
29///
30/// Floating-point number primitives do not satisfy the property (they are not even `Eq`):
31///
32/// ```
33/// assert_eq!(0.0, -0.0);
34/// assert_ne!(0.0.to_string(), (-0.0).to_string());
35///
36/// assert_ne!(f64::NAN, f64::NAN);
37/// assert_eq!(f64::NAN.to_string(), f64::NAN.to_string());
38/// ```
39///
40/// Wrapping any `Display` type with [`fmt_cmp::Cmp`](crate::Cmp) makes it `FmtEq`:
41///
42/// ```
43/// assert_ne!(fmt_cmp::Cmp(0.0), fmt_cmp::Cmp(-0.0));
44/// assert_eq!(fmt_cmp::Cmp(f64::NAN), fmt_cmp::Cmp(f64::NAN));
45/// ```
46pub trait FmtEq: Display + Eq {}
47
48// Blanket impls for `#[fundamental]` pointer types.
49impl<T: FmtEq + ?Sized> FmtEq for &T {}
50impl<T: FmtEq + ?Sized> FmtEq for &mut T {}
51// `Pin<P>` implements `Display` via `<P as Display>` and `PartialEq` with
52// `<P::Target as PartialEq>`. The `P: Borrow<P::Target>` bound should ensure that `<P as Display>`
53// behaves identically with `<P::Target as Display>`.
54// This implementation covers `Pin<&T>`, `Pin<&mut T>` and `Pin<Box<T>>`.
55impl<P: Borrow<<P as Deref>::Target> + Deref + Display> FmtEq for Pin<P> where P::Target: FmtEq {}
56
57impl FmtEq for str {}
58impl FmtEq for bool {}
59
60impl FmtEq for Infallible {}
61
62// `alloc` types.
63#[cfg(feature = "alloc")]
64impl<T: FmtEq + ?Sized> FmtEq for alloc::boxed::Box<T> {}
65#[cfg(feature = "alloc")]
66impl<T: FmtEq + ?Sized> FmtEq for alloc::rc::Rc<T> {}
67#[cfg(feature = "alloc")]
68impl<T: FmtEq + ?Sized> FmtEq for alloc::sync::Arc<T> {}
69// We can assume that `Display` and `PartialEq` behave consistently between `T` and `T::Owned`
70// because of `Borrow<T>` trait's contract, which is implemented by `T::Owned`.
71#[cfg(feature = "alloc")]
72impl<T: FmtEq + alloc::borrow::ToOwned + ?Sized> FmtEq for alloc::borrow::Cow<'_, T> where
73 T::Owned: Display
74{
75}
76#[cfg(feature = "alloc")]
77impl FmtEq for alloc::string::String {}
78
79// `!FmtOrd` types:
80
81// Integral primitives.
82impl FmtEq for u8 {}
83impl FmtEq for u16 {}
84impl FmtEq for u32 {}
85impl FmtEq for u64 {}
86impl FmtEq for u128 {}
87impl FmtEq for usize {}
88impl FmtEq for i8 {}
89impl FmtEq for i16 {}
90impl FmtEq for i32 {}
91impl FmtEq for i64 {}
92impl FmtEq for i128 {}
93impl FmtEq for isize {}
94
95// TODO: Does `char` satisfy the trait contract?