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}