]> git.lizzy.rs Git - rust.git/blob - src/libcore/panic.rs
Implement Display for PanicInfo and Location
[rust.git] / src / libcore / panic.rs
1 // Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Panic support in the standard library.
12
13 #![unstable(feature = "core_panic_info",
14             reason = "newly available in libcore",
15             issue = "44489")]
16
17 use any::Any;
18 use fmt;
19
20 /// A struct providing information about a panic.
21 ///
22 /// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
23 /// function.
24 ///
25 /// [`set_hook`]: ../../std/panic/fn.set_hook.html
26 ///
27 /// # Examples
28 ///
29 /// ```should_panic
30 /// use std::panic;
31 ///
32 /// panic::set_hook(Box::new(|panic_info| {
33 ///     println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
34 /// }));
35 ///
36 /// panic!("Normal panic");
37 /// ```
38 #[stable(feature = "panic_hooks", since = "1.10.0")]
39 #[derive(Debug)]
40 pub struct PanicInfo<'a> {
41     payload: &'a (Any + Send),
42     message: Option<&'a fmt::Arguments<'a>>,
43     location: Location<'a>,
44 }
45
46 impl<'a> PanicInfo<'a> {
47     #![unstable(feature = "panic_internals",
48                 reason = "internal details of the implementation of the `panic!` \
49                           and related macros",
50                 issue = "0")]
51     #[doc(hidden)]
52     pub fn internal_constructor(payload: &'a (Any + Send),
53                                 message: Option<&'a fmt::Arguments<'a>>,
54                                 location: Location<'a>)
55                                 -> Self {
56         PanicInfo { payload, location, message }
57     }
58
59     /// Returns the payload associated with the panic.
60     ///
61     /// This will commonly, but not always, be a `&'static str` or [`String`].
62     ///
63     /// [`String`]: ../../std/string/struct.String.html
64     ///
65     /// # Examples
66     ///
67     /// ```should_panic
68     /// use std::panic;
69     ///
70     /// panic::set_hook(Box::new(|panic_info| {
71     ///     println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
72     /// }));
73     ///
74     /// panic!("Normal panic");
75     /// ```
76     #[stable(feature = "panic_hooks", since = "1.10.0")]
77     pub fn payload(&self) -> &(Any + Send) {
78         self.payload
79     }
80
81     /// If the `panic!` macro from the `core` crate (not from `std`)
82     /// was used with a formatting string and some additional arguments,
83     /// returns that message ready to be used for example with [`fmt::write`]
84     ///
85     /// [`fmt::write`]: ../fmt/fn.write.html
86     #[unstable(feature = "panic_info_message", issue = "44489")]
87     pub fn message(&self) -> Option<&fmt::Arguments> {
88         self.message
89     }
90
91     /// Returns information about the location from which the panic originated,
92     /// if available.
93     ///
94     /// This method will currently always return [`Some`], but this may change
95     /// in future versions.
96     ///
97     /// [`Some`]: ../../std/option/enum.Option.html#variant.Some
98     ///
99     /// # Examples
100     ///
101     /// ```should_panic
102     /// use std::panic;
103     ///
104     /// panic::set_hook(Box::new(|panic_info| {
105     ///     if let Some(location) = panic_info.location() {
106     ///         println!("panic occurred in file '{}' at line {}", location.file(),
107     ///             location.line());
108     ///     } else {
109     ///         println!("panic occurred but can't get location information...");
110     ///     }
111     /// }));
112     ///
113     /// panic!("Normal panic");
114     /// ```
115     #[stable(feature = "panic_hooks", since = "1.10.0")]
116     pub fn location(&self) -> Option<&Location> {
117         // NOTE: If this is changed to sometimes return None,
118         // deal with that case in std::panicking::default_hook.
119         Some(&self.location)
120     }
121 }
122
123 impl<'a> fmt::Display for PanicInfo<'a> {
124     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
125         formatter.write_str("panicked at ")?;
126         if let Some(message) = self.message {
127             write!(formatter, "'{}', ", message)?
128         } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
129             write!(formatter, "'{}', ", payload)?
130         }
131         // NOTE: we cannot use downcast_ref::<String>() here
132         // since String is not available in libcore!
133         // A String payload and no message is what we’d get from `std::panic!`
134         // called with multiple arguments.
135
136         self.location.fmt(formatter)
137     }
138 }
139
140 /// A struct containing information about the location of a panic.
141 ///
142 /// This structure is created by the [`location`] method of [`PanicInfo`].
143 ///
144 /// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location
145 /// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html
146 ///
147 /// # Examples
148 ///
149 /// ```should_panic
150 /// use std::panic;
151 ///
152 /// panic::set_hook(Box::new(|panic_info| {
153 ///     if let Some(location) = panic_info.location() {
154 ///         println!("panic occurred in file '{}' at line {}", location.file(), location.line());
155 ///     } else {
156 ///         println!("panic occurred but can't get location information...");
157 ///     }
158 /// }));
159 ///
160 /// panic!("Normal panic");
161 /// ```
162 #[derive(Debug)]
163 #[stable(feature = "panic_hooks", since = "1.10.0")]
164 pub struct Location<'a> {
165     file: &'a str,
166     line: u32,
167     col: u32,
168 }
169
170 impl<'a> Location<'a> {
171     #![unstable(feature = "panic_internals",
172                 reason = "internal details of the implementation of the `panic!` \
173                           and related macros",
174                 issue = "0")]
175     #[doc(hidden)]
176     pub fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
177         Location { file, line, col }
178     }
179
180     /// Returns the name of the source file from which the panic originated.
181     ///
182     /// # Examples
183     ///
184     /// ```should_panic
185     /// use std::panic;
186     ///
187     /// panic::set_hook(Box::new(|panic_info| {
188     ///     if let Some(location) = panic_info.location() {
189     ///         println!("panic occurred in file '{}'", location.file());
190     ///     } else {
191     ///         println!("panic occurred but can't get location information...");
192     ///     }
193     /// }));
194     ///
195     /// panic!("Normal panic");
196     /// ```
197     #[stable(feature = "panic_hooks", since = "1.10.0")]
198     pub fn file(&self) -> &str {
199         self.file
200     }
201
202     /// Returns the line number from which the panic originated.
203     ///
204     /// # Examples
205     ///
206     /// ```should_panic
207     /// use std::panic;
208     ///
209     /// panic::set_hook(Box::new(|panic_info| {
210     ///     if let Some(location) = panic_info.location() {
211     ///         println!("panic occurred at line {}", location.line());
212     ///     } else {
213     ///         println!("panic occurred but can't get location information...");
214     ///     }
215     /// }));
216     ///
217     /// panic!("Normal panic");
218     /// ```
219     #[stable(feature = "panic_hooks", since = "1.10.0")]
220     pub fn line(&self) -> u32 {
221         self.line
222     }
223
224     /// Returns the column from which the panic originated.
225     ///
226     /// # Examples
227     ///
228     /// ```should_panic
229     /// use std::panic;
230     ///
231     /// panic::set_hook(Box::new(|panic_info| {
232     ///     if let Some(location) = panic_info.location() {
233     ///         println!("panic occurred at column {}", location.column());
234     ///     } else {
235     ///         println!("panic occurred but can't get location information...");
236     ///     }
237     /// }));
238     ///
239     /// panic!("Normal panic");
240     /// ```
241     #[stable(feature = "panic_col", since = "1.25")]
242     pub fn column(&self) -> u32 {
243         self.col
244     }
245 }
246
247 impl<'a> fmt::Display for Location<'a> {
248     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
249         write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
250     }
251 }