use core::fmt::{Debug, Display, Formatter, Result};
use core::ops::Deref;
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct Location(&'static core::panic::Location<'static>);
impl Location {
#[must_use]
#[track_caller]
pub fn current() -> Self {
Self(core::panic::Location::caller())
}
}
impl Deref for Location {
type Target = core::panic::Location<'static>;
fn deref(&self) -> &Self::Target {
self.0
}
}
impl Display for Location {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
write!(f, "{}:{}:{}", self.file(), self.line(), self.column())
}
}
impl Debug for Location {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
Debug::fmt(self.0, f)
}
}
impl snafu::GenerateImplicitData for Location {
#[track_caller]
fn generate() -> Self {
Self::current()
}
}
#[cfg(test)]
mod tests {
use super::*;
use snafu::GenerateImplicitData;
#[test]
fn test_current() {
let loc = Location::current();
assert_eq!(loc.file(), file!());
assert_eq!(loc.line(), line!() - 2);
assert!(loc.column() > 0, "Column should be a positive number");
let loc = Location::generate();
assert_eq!(loc.file(), file!());
assert_eq!(loc.line(), line!() - 2);
assert!(loc.column() > 0, "Column should be a positive number");
}
#[test]
fn test_deref() {
let loc = Location::current();
let file_str = loc.file();
assert_eq!(file_str, file!());
let line_num = loc.line();
assert!(line_num > 0, "Line should be a positive number");
let col_num = loc.column();
assert!(col_num > 0, "Column should be a positive number");
}
#[test]
fn test_generate_implicit_data() {
fn get_location_via_implicit_data() -> Location {
Location::generate()
}
let loc = get_location_via_implicit_data();
assert_eq!(loc.file(), file!());
assert!(loc.line() > 0, "Line should be a positive number");
assert!(loc.column() > 0, "Column should be a positive number");
}
#[cfg(feature = "alloc")]
mod alloc_tests {
use super::*;
use alloc::format;
use alloc::string::ToString;
#[test]
fn test_debug_format() {
let loc = Location::current();
let debug = format!("{:?}", loc);
let display = format!("{}", loc);
assert_ne!(debug, display);
assert!(debug.contains(&format!("{:?}", loc.file())));
assert!(debug.contains(&loc.line().to_string()));
assert!(debug.contains(&loc.column().to_string()));
}
#[test]
fn test_debug_differs_across_call_sites() {
let loc = Location::current();
fn get_another_location() -> Location {
Location::current()
}
let another_loc = get_another_location();
assert_ne!(
format!("{:?}", loc),
format!("{:?}", another_loc),
"Locations from different call sites should differ"
);
}
}
}