1 #![allow(clippy::needless_late_init, clippy::uninlined_format_args)]
2
3 use core::fmt::{self, Debug, Display};
4 use core::str::FromStr;
5 use thiserror::Error;
6
7 pub struct NoFormat;
8
9 #[derive(Debug)]
10 pub struct DebugOnly;
11
12 pub struct DisplayOnly;
13
14 impl Display for DisplayOnly {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result15 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
16 f.write_str("display only")
17 }
18 }
19
20 #[derive(Debug)]
21 pub struct DebugAndDisplay;
22
23 impl Display for DebugAndDisplay {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result24 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25 f.write_str("debug and display")
26 }
27 }
28
29 // Should expand to:
30 //
31 // impl<E> Display for EnumDebugField<E>
32 // where
33 // E: Debug;
34 //
35 // impl<E> Error for EnumDebugField<E>
36 // where
37 // Self: Debug + Display;
38 //
39 #[derive(Error, Debug)]
40 pub enum EnumDebugGeneric<E> {
41 #[error("{0:?}")]
42 FatalError(E),
43 }
44
45 // Should expand to:
46 //
47 // impl<E> Display for EnumFromGeneric<E>;
48 //
49 // impl<E> Error for EnumFromGeneric<E>
50 // where
51 // EnumDebugGeneric<E>: Error + 'static,
52 // Self: Debug + Display;
53 //
54 #[derive(Error, Debug)]
55 pub enum EnumFromGeneric<E> {
56 #[error("enum from generic")]
57 Source(#[from] EnumDebugGeneric<E>),
58 }
59
60 // Should expand to:
61 //
62 // impl<HasDisplay, HasDebug, HasNeither> Display
63 // for EnumCompound<HasDisplay, HasDebug, HasNeither>
64 // where
65 // HasDisplay: Display,
66 // HasDebug: Debug;
67 //
68 // impl<HasDisplay, HasDebug, HasNeither> Error
69 // for EnumCompound<HasDisplay, HasDebug, HasNeither>
70 // where
71 // Self: Debug + Display;
72 //
73 #[derive(Error)]
74 pub enum EnumCompound<HasDisplay, HasDebug, HasNeither> {
75 #[error("{0} {1:?}")]
76 DisplayDebug(HasDisplay, HasDebug),
77 #[error("{0}")]
78 Display(HasDisplay, HasNeither),
79 #[error("{1:?}")]
80 Debug(HasNeither, HasDebug),
81 }
82
83 impl<HasDisplay, HasDebug, HasNeither> Debug for EnumCompound<HasDisplay, HasDebug, HasNeither> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result84 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85 f.write_str("EnumCompound")
86 }
87 }
88
89 #[test]
test_display_enum_compound()90 fn test_display_enum_compound() {
91 let mut instance: EnumCompound<DisplayOnly, DebugOnly, NoFormat>;
92
93 instance = EnumCompound::DisplayDebug(DisplayOnly, DebugOnly);
94 assert_eq!(format!("{}", instance), "display only DebugOnly");
95
96 instance = EnumCompound::Display(DisplayOnly, NoFormat);
97 assert_eq!(format!("{}", instance), "display only");
98
99 instance = EnumCompound::Debug(NoFormat, DebugOnly);
100 assert_eq!(format!("{}", instance), "DebugOnly");
101 }
102
103 // Should expand to:
104 //
105 // impl<E> Display for EnumTransparentGeneric<E>
106 // where
107 // E: Display;
108 //
109 // impl<E> Error for EnumTransparentGeneric<E>
110 // where
111 // E: Error,
112 // Self: Debug + Display;
113 //
114 #[derive(Error, Debug)]
115 pub enum EnumTransparentGeneric<E> {
116 #[error(transparent)]
117 Other(E),
118 }
119
120 // Should expand to:
121 //
122 // impl<E> Display for StructDebugGeneric<E>
123 // where
124 // E: Debug;
125 //
126 // impl<E> Error for StructDebugGeneric<E>
127 // where
128 // Self: Debug + Display;
129 //
130 #[derive(Error, Debug)]
131 #[error("{underlying:?}")]
132 pub struct StructDebugGeneric<E> {
133 pub underlying: E,
134 }
135
136 // Should expand to:
137 //
138 // impl<E> Error for StructFromGeneric<E>
139 // where
140 // StructDebugGeneric<E>: Error + 'static,
141 // Self: Debug + Display;
142 //
143 #[derive(Error, Debug)]
144 pub struct StructFromGeneric<E> {
145 #[from]
146 pub source: StructDebugGeneric<E>,
147 }
148
149 // Should expand to:
150 //
151 // impl<E> Display for StructTransparentGeneric<E>
152 // where
153 // E: Display;
154 //
155 // impl<E> Error for StructTransparentGeneric<E>
156 // where
157 // E: Error,
158 // Self: Debug + Display;
159 //
160 #[derive(Error, Debug)]
161 #[error(transparent)]
162 pub struct StructTransparentGeneric<E>(pub E);
163
164 // Should expand to:
165 //
166 // impl<T: FromStr> Display for AssociatedTypeError<T>
167 // where
168 // T::Err: Display;
169 //
170 // impl<T: FromStr> Error for AssociatedTypeError<T>
171 // where
172 // Self: Debug + Display;
173 //
174 #[derive(Error, Debug)]
175 pub enum AssociatedTypeError<T: FromStr> {
176 #[error("couldn't parse matrix")]
177 Other,
178 #[error("couldn't parse entry: {0}")]
179 EntryParseError(T::Err),
180 }
181
182 // Regression test for https://github.com/dtolnay/thiserror/issues/345
183 #[test]
test_no_bound_on_named_fmt()184 fn test_no_bound_on_named_fmt() {
185 #[derive(Error, Debug)]
186 #[error("{thing}", thing = "...")]
187 struct Error<T> {
188 thing: T,
189 }
190
191 let error = Error { thing: DebugOnly };
192 assert_eq!(error.to_string(), "...");
193 }
194
195 #[test]
test_multiple_bound()196 fn test_multiple_bound() {
197 #[derive(Error, Debug)]
198 #[error("0x{thing:x} 0x{thing:X}")]
199 pub struct Error<T> {
200 thing: T,
201 }
202
203 let error = Error { thing: 0xFFi32 };
204 assert_eq!(error.to_string(), "0xff 0xFF");
205 }
206