1#[derive(Debug)]
3pub struct Location {
4 file: String,
5 line: u32,
6 column: u32,
7}
8
9#[allow(clippy::new_without_default)]
10impl Location {
11 #[track_caller]
12 pub fn new() -> Self {
13 location!()
14 }
15
16 pub fn file(&self) -> &str {
17 &self.file
18 }
19
20 pub fn line(&self) -> u32 {
21 self.line
22 }
23
24 pub fn column(&self) -> u32 {
25 self.column
26 }
27}
28
29impl core::fmt::Display for Location {
30 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
31 write!(f, "{}:{}:{}", self.file, self.line, self.column)
32 }
33}
34
35#[macro_export]
37macro_rules! location {
38 () => {{
39 let caller = ::core::panic::Location::caller();
40 $crate::Location {
41 file: caller.file().to_string(),
42 line: caller.line(),
43 column: caller.column(),
44 }
45 }};
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51
52 #[test]
53 fn test_location() {
54 let file = file!();
55 let column = 24;
57 let line = line!();
58 let location = location!();
59 assert!(matches!(
60 location,
61 Location {
62 file: _,
63 line: _,
64 column: _
65 }
66 ));
67 assert_eq!(location.file(), file);
68 assert_eq!(location.line(), line + 1);
69 assert_eq!(location.column(), column);
70
71 let column = 24;
72 let line = line!();
73 let location = Location::new();
74 assert!(matches!(
75 location,
76 Location {
77 file: _,
78 line: _,
79 column: _
80 }
81 ));
82 assert_eq!(location.file(), file);
83 assert_eq!(location.line(), line + 1);
84 assert_eq!(location.column(), column);
85 }
86}