async_backtrace/location.rs
1use std::fmt::Display;
2
3use futures::Future;
4
5/// Produces a [`Location`] when invoked in a function body.
6///
7/// ```
8/// use async_backtrace::{location, Location};
9///
10/// #[tokio::main]
11/// async fn main() {
12/// assert_eq!(location!().to_string(), "rust_out::main::{{closure}} at backtrace/src/location.rs:8:16");
13///
14/// async {
15/// assert_eq!(location!().to_string(), "rust_out::main::{{closure}}::{{closure}} at backtrace/src/location.rs:11:20");
16/// }.await;
17///
18/// (|| async {
19/// assert_eq!(location!().to_string(), "rust_out::main::{{closure}}::{{closure}}::{{closure}} at backtrace/src/location.rs:15:20");
20/// })().await;
21/// }
22/// ```
23#[macro_export]
24macro_rules! location {
25 () => {{
26 macro_rules! fn_name {
27 () => {{
28 fn type_name_of_val<T: ?Sized>(_: &T) -> &'static str {
29 core::any::type_name::<T>()
30 }
31 type_name_of_val(&|| {})
32 .strip_suffix("::{{closure}}")
33 .unwrap()
34 }};
35 }
36 $crate::Location::from_components(fn_name!(), &(file!(), line!(), column!()))
37 }};
38}
39
40/// A source code location in a function body.
41///
42/// To construct a `Location`, use [`location!()`].
43#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
44pub struct Location {
45 /// The name of the surrounding function.
46 name: Option<&'static str>,
47 /// The file name, line number, and column number on which the surrounding
48 /// function is defined.
49 rest: &'static (&'static str, u32, u32),
50}
51
52impl Location {
53 /// **DO NOT USE!** The signature of this method may change between
54 /// non-breaking releases.
55 #[doc(hidden)]
56 #[inline(always)]
57 pub const fn from_components(
58 name: &'static str,
59 rest: &'static (&'static str, u32, u32),
60 ) -> Self {
61 Self {
62 name: Some(name),
63 rest,
64 }
65 }
66
67 /// Include the given future in taskdumps with this location.
68 ///
69 /// ## Examples
70 /// ```
71 /// # async fn bar() {}
72 /// # async fn baz() {}
73 /// async fn foo() {
74 /// async_backtrace::location!().frame(async move {
75 /// bar().await;
76 /// baz().await;
77 /// }).await
78 /// }
79 /// ```
80 pub fn frame<F>(self, f: F) -> impl Future<Output = F::Output>
81 where
82 F: Future,
83 {
84 crate::Framed::new(f, self)
85 }
86
87 /// Produces the function name associated with this location.
88 pub const fn name(&self) -> Option<&str> {
89 self.name
90 }
91
92 /// Produces the file name associated with this location.
93 pub const fn file(&self) -> &str {
94 self.rest.0
95 }
96
97 /// Produces the line number associated with this location.
98 pub const fn line(&self) -> u32 {
99 self.rest.1
100 }
101
102 /// Produces the column number associated with this location.
103 pub const fn column(&self) -> u32 {
104 self.rest.2
105 }
106}
107
108impl Display for Location {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 let file = self.file();
111 let line = self.line();
112 let column = self.column();
113 if let Some(name) = self.name() {
114 f.write_fmt(format_args!("{name} at {file}:{line}:{column}"))
115 } else {
116 f.write_fmt(format_args!("{file}:{line}:{column}"))
117 }
118 }
119}