Skip to main content

apple_quant_core/log/
ctx.rs

1use std::{
2	fmt::{Display, Formatter},
3	panic::Location,
4};
5
6use tracing::Span;
7
8pub(crate) fn new_ctx(
9	message: Option<String>,
10	location: &'static Location<'static>,
11	anyhow_error: anyhow::Error,
12) -> anyhow::Error {
13	anyhow::Error::new(Ctx {
14		message,
15		location,
16		span: Span::current(),
17		anyhow_error,
18	})
19}
20
21#[derive(Debug)]
22pub(crate) struct Ctx {
23	pub(crate) message: Option<String>,
24	pub(crate) location: &'static Location<'static>,
25	pub(crate) span: Span,
26	pub(crate) anyhow_error: anyhow::Error,
27}
28
29impl Display for Ctx {
30	fn fmt(
31		&self,
32		formatter: &mut Formatter<'_>,
33	) -> std::fmt::Result {
34		match &self.message {
35			Some(
36				message,
37			) => formatter.write_str(message),
38			None => Display::fmt(&self.anyhow_error, formatter),
39		}
40	}
41}
42
43impl std::error::Error for Ctx {
44	fn source(
45		&self,
46	) -> Option<
47		&(dyn std::error::Error + 'static),
48	> {
49		Some(self.anyhow_error.as_ref())
50	}
51}
52
53pub trait CtxExt<T> {
54	fn ctx(
55		self,
56		message: impl Into<String>,
57	) -> anyhow::Result<T>;
58
59	fn ctx_with<F, S>(
60		self,
61		f: F,
62	) -> anyhow::Result<T>
63	where
64		F: FnOnce() -> S,
65		S: Into<String>;
66
67	fn here(
68		self,
69	) -> anyhow::Result<T>;
70}
71
72impl<
73	T,
74	E: Into<anyhow::Error>,
75> CtxExt<T> for Result<T, E> {
76	#[track_caller]
77	fn ctx(
78		self,
79		message: impl Into<String>,
80	) -> anyhow::Result<T> {
81		let location = Location::caller();
82
83		self.map_err(|anyhow_error| {
84			new_ctx(Some(message.into()), location, anyhow_error.into())
85		})
86	}
87
88	#[track_caller]
89	fn ctx_with<F, S>(
90		self,
91		f: F,
92	) -> anyhow::Result<T>
93	where
94		F: FnOnce() -> S,
95		S: Into<String>,
96	{
97		let location = Location::caller();
98
99		self.map_err(|anyhow_error| {
100			new_ctx(Some(f().into()), location, anyhow_error.into())
101		})
102	}
103
104	#[track_caller]
105	fn here(
106		self,
107	) -> anyhow::Result<T> {
108		let location = Location::caller();
109		self.map_err(|anyhow_error| new_ctx(None, location, anyhow_error.into()))
110	}
111}