use std::cmp::Ordering;
use std::fmt::{self, Display, Write};
use std::hash::Hasher;
pub fn eq<T: Display + ?Sized, U: Display + ?Sized>(lhs: &T, rhs: &U) -> bool {
cmp(lhs, rhs) == Ordering::Equal
}
pub fn cmp<T: Display + ?Sized, U: Display + ?Sized>(lhs: &T, rhs: &U) -> Ordering {
struct State {
ret: Ordering,
rhs_is_remaining: bool,
}
struct Rhs<'a, T: ?Sized> {
rhs: &'a T,
pos: usize,
state: State,
}
let state = State {
ret: Ordering::Equal,
rhs_is_remaining: false,
};
let mut adapter = Rhs { rhs, pos: 0, state };
let _ = write!(&mut adapter, "{}", &lhs);
return adapter.state.ret.then(if adapter.state.rhs_is_remaining {
Ordering::Less
} else {
Ordering::Equal
});
struct Lhs<'a> {
lhs: &'a [u8],
skip: usize,
state: &'a mut State,
}
impl<T: Display + ?Sized> Write for Rhs<'_, T> {
fn write_str(&mut self, lhs: &str) -> fmt::Result {
self.state.rhs_is_remaining = false;
let mut adapter = Lhs {
lhs: lhs.as_bytes(),
skip: self.pos,
state: &mut self.state,
};
let _ = write!(&mut adapter, "{}", self.rhs);
let lhs_is_empty = adapter.lhs.is_empty();
if self.state.ret != Ordering::Equal {
return Err(fmt::Error);
}
if !lhs_is_empty {
self.state.ret = Ordering::Greater;
return Err(fmt::Error);
}
self.pos += lhs.len();
Ok(())
}
}
impl Write for Lhs<'_> {
fn write_str(&mut self, rhs: &str) -> fmt::Result {
let skip = self.skip.min(rhs.len());
self.skip -= skip;
let rhs = &rhs.as_bytes()[skip..];
let read = rhs.len().min(self.lhs.len());
self.state.ret = self.lhs[0..read].cmp(&rhs[0..read]);
if self.state.ret != Ordering::Equal {
return Err(fmt::Error);
}
self.lhs = &self.lhs[read..];
if rhs.len() > read {
self.state.rhs_is_remaining = true;
return Err(fmt::Error);
}
Ok(())
}
}
}
pub fn hash<T: Display + ?Sized, H: Hasher>(hashee: &T, hasher: &mut H) {
struct Adapter<'a, H>(&'a mut H);
impl<H: Hasher> Write for Adapter<'_, H> {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.0.write(s.as_bytes());
Ok(())
}
}
write!(Adapter(&mut *hasher), "{}", &hashee).unwrap();
hasher.write_u8(0xff);
}