nu_utils/location.rs
1use serde::{Deserialize, Serialize};
2use std::{
3 borrow::Cow,
4 fmt::{self, Display},
5};
6
7/// A serializable source code location.
8///
9/// This is meant to be a drop in replacement for [`std::panic::Location`]
10/// with the added benefit that it implements [`Serialize`] and [`Deserialize`].
11///
12/// In practice, this is useful when you want to capture caller information
13/// and store it, send it across process boundaries, or include it in serialized data.
14///
15/// For behavior and semantics, see [`std::panic::Location`].
16#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
17pub struct Location {
18 file: Cow<'static, str>,
19 line: u32,
20 column: u32,
21}
22
23impl Location {
24 /// Returns the caller location.
25 ///
26 /// See [`std::panic::Location::caller`] for details.
27 #[track_caller]
28 pub const fn caller() -> Self {
29 let location = std::panic::Location::caller();
30 Self {
31 file: Cow::Borrowed(location.file()),
32 line: location.line(),
33 column: location.column(),
34 }
35 }
36
37 /// Returns the file name.
38 ///
39 /// See [`std::panic::Location::file`] for details.
40 pub const fn file(&self) -> &str {
41 match &self.file {
42 Cow::Borrowed(s) => s,
43 Cow::Owned(s) => s.as_str(),
44 }
45 }
46
47 /// Returns the column number.
48 ///
49 /// See [`std::panic::Location::column`] for details.
50 pub const fn column(&self) -> u32 {
51 self.column
52 }
53
54 /// Returns the line number.
55 ///
56 /// See [`std::panic::Location::line`] for details.
57 pub const fn line(&self) -> u32 {
58 self.line
59 }
60}
61
62/// Converts a static [`std::panic::Location`] into a [`Location`].
63///
64/// `std::panic::Location::caller()` returns a `'static` location, so this
65/// conversion can borrow the file path without allocating.
66impl From<&'static std::panic::Location<'static>> for Location {
67 fn from(location: &'static std::panic::Location<'static>) -> Self {
68 Self {
69 file: Cow::Borrowed(location.file()),
70 line: location.line(),
71 column: location.column(),
72 }
73 }
74}
75
76impl Display for Location {
77 /// Formats this location as `file:line:column`.
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 write!(f, "{}:{}:{}", self.file, self.line, self.column)
80 }
81}