diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs index a092bfb3b0a8a..d324167d6edda 100644 --- a/src/liballoc/fmt.rs +++ b/src/liballoc/fmt.rs @@ -528,6 +528,9 @@ pub use core::fmt::{ArgumentV1, Arguments, write}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; +#[unstable(feature = "best_effort_debug", issue = "0")] +pub use core::fmt::BestEffortDebug; + use string; /// The `format` function takes an [`Arguments`] struct and returns the resulting diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 2727bcaa28a93..8c722cef33066 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -125,6 +125,7 @@ #![feature(exact_chunks)] #![feature(pointer_methods)] #![feature(inclusive_range_fields)] +#![feature(best_effort_debug)] #![cfg_attr(not(test), feature(fn_traits, placement_new_protocol, swap_with_slice, i128))] #![cfg_attr(test, feature(test, box_heap))] diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 67126b496e211..f2eed892f6341 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -1960,5 +1960,77 @@ impl Debug for UnsafeCell { } } +/// A wrapper around a type `T` where `T: Debug` possibly holds. If it does, +/// then the `Debug` impl of `T` will be used in +/// `impl Debug for BestEffortDebug`. +/// Otherwise (if `T: !Debug`), `impl Debug for BestEffortDebug` +/// will output with the type name of `T` and that `T` is `!Debug`. +/// +/// `BestEffortDebug` is useful to avoid `Debug` bounds when trying to debug +/// things in generic code. Without `BestEffortDebug`, your generic call stack +/// will get infected with `T: Debug` bounds until the type is known. +/// +/// This type is particularly useful for macro authors. +/// +/// # Guarantees +/// +/// `BestEffortDebug` makes the guarantee that +/// `impl Debug for BestEffortDebug` exists. +/// However, you should not rely on the stability of `BestEffortDebug`'s +/// output format. In particular, no guarantee is made that the `type_name` +/// is included when `T: !Debug` or that `::fmt` is used when +/// `T: Debug`. +/// +/// # Examples +/// +/// `BestEffortDebug` where `T: Debug` will use the `Debug` +/// implementation of `T`: +/// +/// ```rust +/// #![feature(best_effort_debug)] +/// use std::fmt::BestEffortDebug; +/// +/// assert_eq!(format!("{:?}", BestEffortDebug(0)), "0"); +/// ``` +/// +/// `BestEffortDebug` where `T: !Debug` is `Debug` and outputs the type name: +/// +/// ```rust +/// #![feature(best_effort_debug)] +/// use std::fmt::BestEffortDebug; +/// +/// struct NotDebug; +/// assert_eq!(format!("{:?}", BestEffortDebug(NotDebug)), +/// "[ of type main::NotDebug is !Debug]"); +/// ``` +#[unstable(feature = "best_effort_debug", issue = "0")] +#[derive(Copy, Clone)] +pub struct BestEffortDebug(pub T); + +#[unstable(feature = "best_effort_debug", issue = "0")] +impl Debug for BestEffortDebug { + fn fmt(&self, fmt: &mut Formatter) -> Result { + ::fmt(self, fmt) + } +} + +trait BEDInternal { + fn fmt(&self, fmt: &mut Formatter) -> Result; +} + +impl BEDInternal for BestEffortDebug { + default fn fmt(&self, fmt: &mut Formatter) -> Result { + use intrinsics::type_name; + write!(fmt, "[ of type {} is !Debug]", + unsafe { type_name::() }) + } +} + +impl BEDInternal for BestEffortDebug { + fn fmt(&self, fmt: &mut Formatter) -> Result { + self.0.fmt(fmt) + } +} + // If you expected tests to be here, look instead at the run-pass/ifmt.rs test, // it's a lot easier than creating all of the rt::Piece structures here. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 9aebe2e4ee4b4..cb4f934b11cb2 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -101,6 +101,7 @@ #![feature(unboxed_closures)] #![feature(untagged_unions)] #![feature(unwind_attributes)] +#![feature(core_intrinsics)] #![cfg_attr(stage0, allow(unused_attributes))] #![cfg_attr(stage0, feature(never_type))]