• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 use std::{
18     any::type_name,
19     fmt::{self, Debug, Display, Formatter},
20 };
21 
22 /// Provides access to a best-effort implementation of [Display].
23 ///
24 /// [BestEffortDisplay] creates a wrapper that implements [Display] for the
25 /// provided type.
26 ///   * If `T` implements [Display], the wrapper will forward to `T`'s [Display]
27 ///     implementation.
28 ///   * If `T` does not implement [Display], but does implement [Debug], the
29 ///     wrapper will use to `T`'s [Debug] implementation.
30 ///   * If `T` implements neither [Display] nor [Debug], the wrapper will
31 ///     display `T`'s [type_name].
32 ///
33 /// The wrapper should be created with the following expression. The
34 /// [DisplayKind], [DebugKind], and [TypenameKind] traits need to be in scope.
35 /// (` as _` is fine; the traits just need to be in scope for method resolution;
36 /// the actual trait names don't need to be accessible.)
37 ///
38 /// ```
39 /// # fn example() -> impl std::fmt::Display {
40 /// # let x: usize = 5;
41 /// # use test::__internal_macro_utils::{
42 /// #     BestEffortDisplay,
43 /// #     DisplayKind as _,
44 /// #     DebugKind as _,
45 /// #     TypenameKind as _,
46 /// # };
47 /// (&&&BestEffortDisplay(&x)).display_kind().wrap(x)
48 /// # }
49 /// ```
50 ///
51 /// # Examples
52 ///
53 /// ```
54 /// use test::__internal_macro_utils::BestEffortDisplay;
55 ///
56 /// struct NeitherDisplayOrDebug;
57 /// #[derive(Debug)]
58 /// struct DebugOnlyType;
59 /// struct DisplayType;
60 ///
61 /// impl std::fmt::Display for DisplayType {
62 ///     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
63 ///         write!(f, "Fancy Description")
64 ///     }
65 /// }
66 ///
67 /// let a = DisplayType;
68 /// let b = DebugOnlyType;
69 /// let c = NeitherDisplayOrDebug;
70 ///
71 /// use test::__internal_macro_utils::{DisplayKind as _, DebugKind as _, TypenameKind as _};
72 /// let a = (&&&BestEffortDisplay(&a)).display_kind().wrap(a);
73 /// let b = (&&&BestEffortDisplay(&b)).display_kind().wrap(b);
74 /// let c = (&&&BestEffortDisplay(&c)).display_kind().wrap(c);
75 ///
76 /// assert_eq!(a.to_string(), "Fancy Description");
77 /// assert_eq!(b.to_string(), "DebugOnlyType");
78 /// assert_eq!(c.to_string(),
79 ///            format!("value of type {}",
80 ///                    std::any::type_name::<NeitherDisplayOrDebug>()));
81 /// ```
82 ///
83 /// [BestEffortDisplay] is implemented with [autoref specialization], which has
84 /// some limitations, namely that we have to know that `T` implements [Display]
85 /// at `get`'s callsite. As a result, it's mostly only useful inside macros.
86 /// Because the specialization has [more than two levels], we're acutually using
87 /// auto*de*ref, which is why the usage requires calling `display_kind` on
88 /// `&&&Self` (one more `&` than the highest priority `*Kind` impl).
89 ///
90 /// Once stable Rust supports [min_specialization], this should be replaced to
91 /// use that instead.
92 ///
93 /// [autoref specialization]: https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md
94 /// [more than two levels]: https://lukaskalbertodt.github.io/2019/12/05/generalized-autoref-based-specialization.html#using-autoderef-for--two-specialization-levels
95 /// [min_specialization]: https://doc.rust-lang.org/nightly/unstable-book/language-features/min-specialization.html#min_specialization
96 pub struct BestEffortDisplay<T>(pub T);
97 
98 // When calling `(&&&BestEffortDisplay(&x)).display_kind()`, autoderef
99 // prioritizes the `DisplayKind` impl if it applies, then the `DebugKind` impl
100 // if it applies, then `TypenameKind`, which always applies.
101 impl<T: Display> DisplayKind for &&BestEffortDisplay<&T> {}
102 impl<T: Debug> DebugKind for &BestEffortDisplay<&T> {}
103 impl<T> TypenameKind for BestEffortDisplay<&T> {}
104 
105 /// Constructs [Display] wrappers for types that implement [Display].
106 pub struct DisplayTag;
107 /// Constructs [Display] wrappers for types that implement [Debug].
108 pub struct DebugTag;
109 /// Constructs [Display] wrappers for any type.
110 pub struct TypenameTag;
111 
112 /// Implements [Display] by delegating to `T`'s [Display] implementation.
113 pub struct DisplayDisplayer<T>(T);
114 /// Implements [Display] by delegating to `T`'s [Debug] implementation.
115 pub struct DebugDisplayer<T>(T);
116 /// Implements [Display] by printing `T`'s [type_name].
117 pub struct TypenameDisplayer<T>(T);
118 
119 pub trait DisplayKind {
120     #[inline]
display_kind(&self) -> DisplayTag121     fn display_kind(&self) -> DisplayTag {
122         DisplayTag
123     }
124 }
125 pub trait DebugKind {
126     #[inline]
display_kind(&self) -> DebugTag127     fn display_kind(&self) -> DebugTag {
128         DebugTag
129     }
130 }
131 pub trait TypenameKind {
132     #[inline]
display_kind(&self) -> TypenameTag133     fn display_kind(&self) -> TypenameTag {
134         TypenameTag
135     }
136 }
137 
138 impl DisplayTag {
wrap<T: Display>(self, t: T) -> DisplayDisplayer<T>139     pub fn wrap<T: Display>(self, t: T) -> DisplayDisplayer<T> {
140         DisplayDisplayer(t)
141     }
142 }
143 impl DebugTag {
wrap<T: Debug>(self, t: T) -> DebugDisplayer<T>144     pub fn wrap<T: Debug>(self, t: T) -> DebugDisplayer<T> {
145         DebugDisplayer(t)
146     }
147 }
148 impl TypenameTag {
wrap<T>(self, t: T) -> TypenameDisplayer<T>149     pub fn wrap<T>(self, t: T) -> TypenameDisplayer<T> {
150         TypenameDisplayer(t)
151     }
152 }
153 
154 impl<T: Display> Display for DisplayDisplayer<T> {
fmt(&self, f: &mut Formatter) -> fmt::Result155     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
156         write!(f, "{}", self.0)
157     }
158 }
159 impl<T: Debug> Display for DebugDisplayer<T> {
fmt(&self, f: &mut Formatter) -> fmt::Result160     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
161         write!(f, "{:?}", self.0)
162     }
163 }
164 impl<T> Display for TypenameDisplayer<T> {
fmt(&self, f: &mut Formatter) -> fmt::Result165     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
166         write!(f, "value of type {}", type_name::<T>())
167     }
168 }
169