Add a TypeNameToDebug formatter to zebra_chain (#2466)

* Add a TypeNameToDebug formatter to zebra_chain

This formatter makes it much easier to diagnose proptest errors.
It will be used in a future PR.

Implement Arbitrary and DerefMut for all the formatters.

Also make the formatter type bounds consistent,
to produce better compiler errors.

* Clarify how TypeNameToDebug actually works

Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com>

Co-authored-by: Janito Vaqueiro Ferreira Filho <janito.vff@gmail.com>
This commit is contained in:
teor 2021-07-09 12:40:19 +10:00 committed by GitHub
parent 23fe2c2e94
commit 64be7fddb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 93 additions and 14 deletions

View File

@ -2,20 +2,23 @@
use std::{fmt, ops}; use std::{fmt, ops};
/// Wrapper to override `Debug`, redirecting it to the `Display` impl. #[cfg(any(test, feature = "proptest-impl"))]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] use proptest::prelude::*;
pub struct DisplayToDebug<T>(pub T); #[cfg(any(test, feature = "proptest-impl"))]
use proptest_derive::Arbitrary;
impl<T> fmt::Debug for DisplayToDebug<T> /// Wrapper to override `Debug`, redirecting it to only output the type's name.
where #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
T: fmt::Display, #[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
{ pub struct TypeNameToDebug<T>(pub T);
impl<T> fmt::Debug for TypeNameToDebug<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f) f.write_str(std::any::type_name::<T>())
} }
} }
impl<T> ops::Deref for DisplayToDebug<T> { impl<T> ops::Deref for TypeNameToDebug<T> {
type Target = T; type Target = T;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -23,7 +26,44 @@ impl<T> ops::Deref for DisplayToDebug<T> {
} }
} }
impl<T> From<T> for DisplayToDebug<T> { impl<T> ops::DerefMut for TypeNameToDebug<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> From<T> for TypeNameToDebug<T> {
fn from(t: T) -> Self {
Self(t)
}
}
/// Wrapper to override `Debug`, redirecting it to the `Display` impl.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
pub struct DisplayToDebug<T: fmt::Display>(pub T);
impl<T: fmt::Display> fmt::Debug for DisplayToDebug<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T: fmt::Display> ops::Deref for DisplayToDebug<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: fmt::Display> ops::DerefMut for DisplayToDebug<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T: fmt::Display> From<T> for DisplayToDebug<T> {
fn from(t: T) -> Self { fn from(t: T) -> Self {
Self(t) Self(t)
} }
@ -34,7 +74,10 @@ impl<T> From<T> for DisplayToDebug<T> {
/// For collections and exact size iterators, it only displays the /// For collections and exact size iterators, it only displays the
/// collection/iterator type, the item type, and the length. /// collection/iterator type, the item type, and the length.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SummaryDebug<CollectionOrIter>(pub CollectionOrIter); pub struct SummaryDebug<CollectionOrIter>(pub CollectionOrIter)
where
CollectionOrIter: IntoIterator + Clone,
<CollectionOrIter as IntoIterator>::IntoIter: ExactSizeIterator;
impl<CollectionOrIter> fmt::Debug for SummaryDebug<CollectionOrIter> impl<CollectionOrIter> fmt::Debug for SummaryDebug<CollectionOrIter>
where where
@ -52,7 +95,11 @@ where
} }
} }
impl<CollectionOrIter> ops::Deref for SummaryDebug<CollectionOrIter> { impl<CollectionOrIter> ops::Deref for SummaryDebug<CollectionOrIter>
where
CollectionOrIter: IntoIterator + Clone,
<CollectionOrIter as IntoIterator>::IntoIter: ExactSizeIterator,
{
type Target = CollectionOrIter; type Target = CollectionOrIter;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
@ -60,7 +107,21 @@ impl<CollectionOrIter> ops::Deref for SummaryDebug<CollectionOrIter> {
} }
} }
impl<CollectionOrIter> From<CollectionOrIter> for SummaryDebug<CollectionOrIter> { impl<CollectionOrIter> ops::DerefMut for SummaryDebug<CollectionOrIter>
where
CollectionOrIter: IntoIterator + Clone,
<CollectionOrIter as IntoIterator>::IntoIter: ExactSizeIterator,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<CollectionOrIter> From<CollectionOrIter> for SummaryDebug<CollectionOrIter>
where
CollectionOrIter: IntoIterator + Clone,
<CollectionOrIter as IntoIterator>::IntoIter: ExactSizeIterator,
{
fn from(collection: CollectionOrIter) -> Self { fn from(collection: CollectionOrIter) -> Self {
Self(collection) Self(collection)
} }
@ -68,7 +129,8 @@ impl<CollectionOrIter> From<CollectionOrIter> for SummaryDebug<CollectionOrIter>
impl<CollectionOrIter> IntoIterator for SummaryDebug<CollectionOrIter> impl<CollectionOrIter> IntoIterator for SummaryDebug<CollectionOrIter>
where where
CollectionOrIter: IntoIterator, CollectionOrIter: IntoIterator + Clone,
<CollectionOrIter as IntoIterator>::IntoIter: ExactSizeIterator,
{ {
type Item = <CollectionOrIter as IntoIterator>::Item; type Item = <CollectionOrIter as IntoIterator>::Item;
type IntoIter = <CollectionOrIter as IntoIterator>::IntoIter; type IntoIter = <CollectionOrIter as IntoIterator>::IntoIter;
@ -77,3 +139,20 @@ where
self.0.into_iter() self.0.into_iter()
} }
} }
#[cfg(any(test, feature = "proptest-impl"))]
impl<CollectionOrIter> Arbitrary for SummaryDebug<CollectionOrIter>
where
CollectionOrIter: Arbitrary + IntoIterator + Clone + 'static,
<CollectionOrIter as IntoIterator>::IntoIter: ExactSizeIterator,
{
type Parameters = <CollectionOrIter as Arbitrary>::Parameters;
fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
CollectionOrIter::arbitrary_with(args)
.prop_map_into()
.boxed()
}
type Strategy = BoxedStrategy<Self>;
}