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}