use std::error::Error;
use std::fmt::{self, Debug, Display};
use std::marker::PhantomData;
use std::ops::AddAssign;
use std::time::Duration;
use cgmath::{Matrix4, Point3, Vector2, Vector3, Vector4};
use instant::Instant;
mod yield_progress;
pub use yield_progress::*;
pub trait CustomFormat<F: Copy> {
fn custom_format(&self, format_type: F) -> CustomFormatWrapper<'_, F, Self> {
CustomFormatWrapper(format_type, self)
}
fn fmt(&self, fmt: &mut fmt::Formatter<'_>, format_type: F) -> fmt::Result;
}
#[derive(Eq, PartialEq)]
pub struct CustomFormatWrapper<'a, F: Copy, T: CustomFormat<F> + ?Sized>(F, &'a T);
impl<'a, F: Copy, T: CustomFormat<F>> Debug for CustomFormatWrapper<'a, F, T> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
<T as CustomFormat<F>>::fmt(self.1, fmt, self.0)
}
}
impl<'a, F: Copy, T: CustomFormat<F>> Display for CustomFormatWrapper<'a, F, T> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
<T as CustomFormat<F>>::fmt(self.1, fmt, self.0)
}
}
impl<F: Copy, T: CustomFormat<F>> CustomFormat<F> for &'_ T {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>, format_type: F) -> fmt::Result {
<T as CustomFormat<F>>::fmt(&**self, fmt, format_type)
}
}
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub(crate) struct Unquote;
impl CustomFormat<Unquote> for String {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>, _: Unquote) -> fmt::Result {
write!(fmt, "{self}")
}
}
impl CustomFormat<Unquote> for &'_ str {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>, _: Unquote) -> fmt::Result {
write!(fmt, "{self}")
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub(crate) struct TypeName;
impl<T> CustomFormat<TypeName> for PhantomData<T> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>, _: TypeName) -> fmt::Result {
write!(fmt, "{}", std::any::type_name::<T>())
}
}
#[allow(clippy::exhaustive_structs)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ConciseDebug;
impl<T: CustomFormat<ConciseDebug>, const N: usize> CustomFormat<ConciseDebug> for [T; N] {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>, format_type: ConciseDebug) -> fmt::Result {
fmt.debug_list()
.entries(self.iter().map(|item| item.custom_format(format_type)))
.finish()
}
}
impl<S: Debug> CustomFormat<ConciseDebug> for Point3<S> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>, _: ConciseDebug) -> fmt::Result {
write!(fmt, "({:+.3?}, {:+.3?}, {:+.3?})", self.x, self.y, self.z)
}
}
impl<S: Debug> CustomFormat<ConciseDebug> for Matrix4<S> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>, _: ConciseDebug) -> fmt::Result {
write!(
fmt,
"\n[{:?},\n {:?},\n {:?},\n {:?}]",
self.x.custom_format(ConciseDebug),
self.y.custom_format(ConciseDebug),
self.z.custom_format(ConciseDebug),
self.w.custom_format(ConciseDebug)
)
}
}
impl<S: Debug> CustomFormat<ConciseDebug> for Vector2<S> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>, _: ConciseDebug) -> fmt::Result {
write!(fmt, "({:+.3?}, {:+.3?})", self.x, self.y)
}
}
impl<S: Debug> CustomFormat<ConciseDebug> for Vector3<S> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>, _: ConciseDebug) -> fmt::Result {
write!(fmt, "({:+.3?}, {:+.3?}, {:+.3?})", self.x, self.y, self.z)
}
}
impl<S: Debug> CustomFormat<ConciseDebug> for Vector4<S> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>, _: ConciseDebug) -> fmt::Result {
write!(
fmt,
"({:+.3?}, {:+.3?}, {:+.3?}, {:+.3?})",
self.x, self.y, self.z, self.w
)
}
}
#[allow(clippy::exhaustive_structs)]
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub struct StatusText;
impl CustomFormat<StatusText> for Duration {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>, _: StatusText) -> fmt::Result {
write!(fmt, "{:5.2?} ms", (self.as_micros() as f32) / 1000.0)
}
}
#[doc(hidden)] #[derive(Clone, Copy, Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct ErrorChain<'a>(pub &'a (dyn Error + 'a));
impl Display for ErrorChain<'_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
format_error_chain(fmt, self.0)
}
}
fn format_error_chain(fmt: &mut fmt::Formatter<'_>, mut error: &(dyn Error + '_)) -> fmt::Result {
write!(fmt, "{error}")?;
while let Some(source) = error.source() {
error = source;
write!(fmt, "\n\nCaused by:\n {error}")?;
}
Ok(())
}
#[doc(hidden)] #[derive(Debug)]
pub struct MapExtend<'a, A, B, T, F>
where
T: Extend<B>,
F: Fn(A) -> B,
{
target: &'a mut T,
function: F,
_input: PhantomData<fn(A)>,
}
impl<'a, A, B, T, F> MapExtend<'a, A, B, T, F>
where
T: Extend<B>,
F: Fn(A) -> B,
{
pub fn new(target: &'a mut T, function: F) -> Self {
Self {
target,
function,
_input: PhantomData,
}
}
}
impl<'a, A, B, T, F> Extend<A> for MapExtend<'a, A, B, T, F>
where
T: Extend<B>,
F: Fn(A) -> B,
{
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = A>,
{
self.target.extend(iter.into_iter().map(&self.function));
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
#[non_exhaustive]
pub struct TimeStats {
pub count: usize,
pub sum: Duration,
pub min: Option<Duration>,
pub max: Duration,
}
impl TimeStats {
pub const fn one(duration: Duration) -> Self {
Self {
count: 1,
sum: duration,
min: Some(duration),
max: duration,
}
}
pub(crate) fn record_consecutive_interval(
&mut self,
last_marked_instant: &mut Instant,
now: Instant,
) -> Duration {
let previous = *last_marked_instant;
*last_marked_instant = now;
let duration = now.duration_since(previous);
*self += Self::one(duration);
duration
}
}
impl AddAssign for TimeStats {
fn add_assign(&mut self, rhs: Self) {
*self = TimeStats {
count: self.count + rhs.count,
sum: self.sum + rhs.sum,
min: self.min.map_or(rhs.min, |value| Some(value.min(rhs.min?))),
max: self.max.max(rhs.max),
};
}
}
impl Display for TimeStats {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.min {
None => write!(
f,
"(-------- .. {}) for {:3}, total {}",
self.max.custom_format(StatusText),
self.count,
self.sum.custom_format(StatusText),
),
Some(min) => write!(
f,
"({} .. {}) for {:3}, total {}",
min.custom_format(StatusText),
self.max.custom_format(StatusText),
self.count,
self.sum.custom_format(StatusText),
),
}
}
}
#[doc(hidden)]
pub fn assert_send_sync<T: Send + Sync>() {
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basic_concise_debug() {
#[derive(Debug)]
struct Foo;
impl CustomFormat<ConciseDebug> for Foo {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>, _: ConciseDebug) -> fmt::Result {
write!(fmt, "<Foo>")
}
}
assert_eq!("Foo", format!("{Foo:?}"));
assert_eq!("<Foo>", format!("{:?}", Foo.custom_format(ConciseDebug)));
}
#[test]
fn error_chain() {
#[derive(Debug, thiserror::Error)]
#[error("TestError1")]
struct TestError1;
#[derive(Debug, thiserror::Error)]
#[error("TestError2")]
struct TestError2(#[source] TestError1);
assert_eq!(
format!("{}", ErrorChain(&TestError2(TestError1))),
"TestError2\n\nCaused by:\n TestError1"
);
}
}