Skip to content

Instantly share code, notes, and snippets.

@tesaguri
Last active September 15, 2024 00:24
Show Gist options
  • Select an option

  • Save tesaguri/64bbe8aa010736a84c5fed2bda9946fd to your computer and use it in GitHub Desktop.

Select an option

Save tesaguri/64bbe8aa010736a84c5fed2bda9946fd to your computer and use it in GitHub Desktop.
Experiment to implement a `Debug`-like trait for any type using specialization.
#![feature(specialization)]
// #![feature(min_specialization)] // error: cannot specialize on trait `Debug`
use core::fmt::{self, Debug, Formatter};
#[test]
#[should_panic(
expected = "called `Result::unwrap_any()` on an `Err` value: playground::unwrap_non_debug::NonDebug"
)]
fn unwrap_non_debug() {
struct NonDebug;
Err::<(), _>(NonDebug).unwrap_any();
}
#[test]
#[should_panic(expected = "called `Result::unwrap_any()` on an `Err` value: \"hello\"")]
fn unwrap_debug() {
Err::<(), _>("hello").unwrap_any();
}
pub trait DebugAny {
fn fmt(&self, f: &mut Formatter) -> fmt::Result;
fn force_debug(&self) -> impl Debug {
ForceDebug(self)
}
}
impl<T: ?Sized> DebugAny for T {
default fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.write_str(core::any::type_name::<Self>())
}
}
impl<T: ?Sized + Debug> DebugAny for T {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
Debug::fmt(self, f)
}
}
struct ForceDebug<'a, T: ?Sized>(&'a T);
impl<'a, T: ?Sized> Debug for ForceDebug<'a, T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
DebugAny::fmt(self.0, f)
}
}
pub trait UnwrapAnyExt {
type Item;
fn unwrap_any(self) -> Self::Item;
}
impl<T, E: DebugAny> UnwrapAnyExt for Result<T, E> {
type Item = T;
fn unwrap_any(self) -> T {
match self {
Ok(t) => t,
Err(e) => panic!(
"called `Result::unwrap_any()` on an `Err` value: {:?}",
e.force_debug(),
),
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment