error_location/
lib.rs

1//! # error-location
2//!
3//! A lightweight utility for capturing and displaying error locations in Rust.
4//!
5//! This crate provides a simple wrapper around `std::panic::Location` to make it easier
6//! to track where errors originate in your code. It's particularly useful when building
7//! custom error types with crates like `thiserror`.
8//!
9//! ## Usage
10//!
11//! ```rust, ignore
12//! use error_location::ErrorLocation;
13//! use std::panic::Location;
14//!
15//! #[track_caller]
16//! fn might_fail() -> Result<(), String> {
17//!     let location = ErrorLocation::from(Location::caller());
18//!     Err(format!("Something went wrong at {}", location))
19//! }
20//!
21//! fn main() {
22//!     match might_fail() {
23//!         Ok(_) => println!("Success!"),
24//!         Err(e) => eprintln!("Error: {}", e),
25//!     }
26//! }
27//! ```
28//!
29//! ## Example with `thiserror`
30//!
31//! ```rust, ignore
32//! use error_location::ErrorLocation;
33//! use std::panic::Location;
34//! use thiserror::Error;
35//!
36//! #[derive(Error, Debug)]
37//! pub enum MyError {
38//!     #[error("Database error at {location}: {message}")]
39//!     Database {
40//!         message: String,
41//!         location: ErrorLocation,
42//!     },
43//! }
44//!
45//! #[track_caller]
46//! fn query_database() -> Result<(), MyError> {
47//!     Err(MyError::Database {
48//!         message: "Connection failed".to_string(),
49//!         location: ErrorLocation::from(Location::caller()),
50//!     })
51//! }
52//! ```
53
54#![deny(missing_docs)]
55#![deny(unsafe_code)]
56#![warn(clippy::all)]
57#![cfg_attr(docsrs, feature(doc_cfg))]
58
59use std::fmt::{Display, Formatter, Result as FormatResult};
60use std::panic::Location as PanicLocation;
61
62/// A lightweight wrapper around `std::panic::Location` for tracking error origins.
63///
64/// This struct captures the file, line, and column information of where an error
65/// was created. It's designed to be used with the `#[track_caller]` attribute.
66///
67/// # Examples
68///
69/// ```rust, ignore
70/// use error_location::ErrorLocation;
71/// use std::panic::Location;
72///
73/// #[track_caller]
74/// fn create_error() -> ErrorLocation {
75///     ErrorLocation::from(Location::caller())
76/// }
77///
78/// let location = create_error();
79/// println!("Error occurred at: {}", location);
80/// ```
81#[derive(Debug, Clone, Copy)]
82pub struct ErrorLocation {
83    /// The file path where the error occurred
84    pub file: &'static str,
85    /// The line number where the error occurred
86    pub line: u32,
87    /// The column number where the error occurred
88    pub column: u32,
89}
90
91impl ErrorLocation {
92    /// Creates an `ErrorLocation` from a `std::panic::Location`.
93    ///
94    /// This method is designed to be used with `Location::caller()` in functions
95    /// marked with `#[track_caller]`.
96    ///
97    /// # Examples
98    ///
99    /// ```rust, ignore
100    /// use error_location::ErrorLocation;
101    /// use std::panic::Location;
102    ///
103    /// #[track_caller]
104    /// fn get_location() -> ErrorLocation {
105    ///     ErrorLocation::from(Location::caller())
106    /// }
107    /// ```
108    pub const fn from(location: &'static PanicLocation<'static>) -> Self {
109        Self {
110            file: location.file(),
111            line: location.line(),
112            column: location.column(),
113        }
114    }
115}
116
117impl Display for ErrorLocation {
118    fn fmt(&self, formatter: &mut Formatter<'_>) -> FormatResult {
119        write!(formatter, "[{}:{}:{}]", self.file, self.line, self.column)
120    }
121}