partialdebug/no_specialization.rs
1//! Trait detection logic without using specialization.
2//!
3//! Inspired by the [impls](https://github.com/nvzqz/impls#how-it-works) crate.
4//!
5//! [`DebugDetector`] implements the method `as_debug` twice.
6//! Once as a conditionally implemented inherent method always returning `Some(&dyn Debug)` and once as a trait method always returning `None`.
7//!
8//! An inherent method has priority over a trait method of the same name.
9//!
10//! Using `DebugDetector::<SomeType>::as_debug(&something)` then acts as a trait detector.
11//!
12//! Note that if `SomeType` is generic the detector won't work.
13
14use core::fmt::Debug;
15
16/// Fallback trait implemented by DebugDetector.
17pub trait NotDebug: private::Sealed {
18    /// Returns `None`
19    #[allow(clippy::wrong_self_convention)]
20    fn as_debug<T>(_: &T) -> Option<&dyn Debug> {
21        None
22    }
23}
24
25impl<T> NotDebug for DebugDetector<T> {}
26
27/// Zero size struct, acting as a trait Detector.
28pub struct DebugDetector<T>(core::marker::PhantomData<T>);
29
30impl<T: Debug> DebugDetector<T> {
31    /// Returns the passed in argument as `Some(&dyn Debug).`
32    #[allow(clippy::unnecessary_wraps, clippy::wrong_self_convention)]
33    pub fn as_debug(it: &T) -> Option<&dyn Debug> {
34        Some(it)
35    }
36}
37
38mod private {
39    pub trait Sealed {}
40
41    // Implement for those same types, but no others.
42    impl<T> Sealed for super::DebugDetector<T> {}
43}