spdlog/
source_location.rs

1use std::path;
2
3/// Represents a location in source code.
4///
5/// Usually users don't need to construct it manually, but if you do, use macro
6/// [`source_location_current`].
7///
8/// ## Schema
9///
10/// This struct is implemented [`serde::Serialize`] if crate feature `serde` is
11/// enabled.
12///
13/// | Field         | Type   |
14/// |---------------|--------|
15/// | `module_path` | String |
16/// | `file`        | String |
17/// | `line`        | u32    |
18/// | `column`      | u32    |
19///
20/// [`source_location_current`]: crate::source_location_current
21#[derive(Clone, Hash, Debug)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize))]
23pub struct SourceLocation {
24    module_path: &'static str,
25    file: &'static str,
26    line: u32,
27    column: u32,
28}
29
30impl SourceLocation {
31    // Usually users don't need to construct it manually, but if you do, use macro
32    // [`source_location_current`].
33    #[doc(hidden)]
34    #[must_use]
35    pub fn __new(module_path: &'static str, file: &'static str, line: u32, column: u32) -> Self {
36        Self {
37            module_path,
38            file,
39            line,
40            column,
41        }
42    }
43
44    /// Gets the module path.
45    #[must_use]
46    pub fn module_path(&self) -> &'static str {
47        self.module_path
48    }
49
50    /// Gets the source file.
51    ///
52    /// It returns a string slice like this: `src/main.rs`
53    #[must_use]
54    pub fn file(&self) -> &'static str {
55        self.file
56    }
57
58    /// Gets the source file name.
59    ///
60    /// It returns a string slice like this: `main.rs`
61    #[must_use]
62    pub fn file_name(&self) -> &'static str {
63        if let Some(index) = self.file.rfind(path::MAIN_SEPARATOR) {
64            &self.file[index + 1..]
65        } else {
66            self.file
67        }
68    }
69
70    /// Gets the line number in the source file.
71    #[must_use]
72    pub fn line(&self) -> u32 {
73        self.line
74    }
75
76    /// Gets the column number in the source file.
77    #[must_use]
78    pub fn column(&self) -> u32 {
79        self.column
80    }
81
82    #[cfg(feature = "log")]
83    #[must_use]
84    pub(crate) fn from_log_crate_record(record: &log::Record) -> Option<Self> {
85        let (module_path, file, line) = (
86            record.module_path_static(),
87            record.file_static(),
88            record.line(),
89        );
90
91        match (module_path, file, line) {
92            (None, None, None) => None,
93            _ => Some(Self {
94                module_path: module_path.unwrap_or(""),
95                file: file.unwrap_or(""),
96                line: line.unwrap_or(0),
97                column: 0,
98            }),
99        }
100    }
101}
102
103/// Constructs a [`SourceLocation`] with current source location.
104///
105/// The return type of this macro is `Option<SourceLocation>`. Returns `None` if
106/// the feature `source-location` is not enabled.
107///
108/// # Examples
109///
110/// ```
111/// use spdlog::{SourceLocation, source_location_current};
112///
113/// let source_location: Option<SourceLocation> = source_location_current!();
114/// ```
115#[macro_export]
116macro_rules! source_location_current {
117    () => {
118        $crate::__private_source_location_current_inner!()
119    };
120}
121
122#[macro_export]
123#[doc(hidden)]
124#[cfg(feature = "source-location")]
125macro_rules! __private_source_location_current_inner {
126    () => {
127        Some($crate::SourceLocation::__new(
128            module_path!(),
129            file!(),
130            line!(),
131            column!(),
132        ))
133    };
134}
135
136#[macro_export]
137#[doc(hidden)]
138#[cfg(not(feature = "source-location"))]
139macro_rules! __private_source_location_current_inner {
140    () => {
141        Option::<$crate::SourceLocation>::None
142    };
143}
144
145#[cfg(test)]
146mod tests {
147    #[test]
148    fn option_type_inference() {
149        // When feature `source-location` is disabled, the macro must return a full
150        // qualified `None`, otherwise the compiler cannot infer the `Option` type.
151        _ = source_location_current!();
152    }
153}