apple-quant-core 0.2.0

Apple Quant's core library.
Documentation
use std::{
	fmt::{Display, Formatter},
	panic::Location,
};

use tracing::Span;

pub(crate) fn new_ctx(
	message: Option<String>,
	location: &'static Location<'static>,
	anyhow_error: anyhow::Error,
) -> anyhow::Error {
	anyhow::Error::new(Ctx {
		message,
		location,
		span: Span::current(),
		anyhow_error,
	})
}

#[derive(Debug)]
pub(crate) struct Ctx {
	pub(crate) message: Option<String>,
	pub(crate) location: &'static Location<'static>,
	pub(crate) span: Span,
	pub(crate) anyhow_error: anyhow::Error,
}

impl Display for Ctx {
	fn fmt(
		&self,
		formatter: &mut Formatter<'_>,
	) -> std::fmt::Result {
		match &self.message {
			Some(
				message,
			) => formatter.write_str(message),
			None => Display::fmt(&self.anyhow_error, formatter),
		}
	}
}

impl std::error::Error for Ctx {
	fn source(
		&self,
	) -> Option<
		&(dyn std::error::Error + 'static),
	> {
		Some(self.anyhow_error.as_ref())
	}
}

pub trait CtxExt<T> {
	fn ctx(
		self,
		message: impl Into<String>,
	) -> anyhow::Result<T>;

	fn ctx_with<F, S>(
		self,
		f: F,
	) -> anyhow::Result<T>
	where
		F: FnOnce() -> S,
		S: Into<String>;

	fn here(
		self,
	) -> anyhow::Result<T>;
}

impl<
	T,
	E: Into<anyhow::Error>,
> CtxExt<T> for Result<T, E> {
	#[track_caller]
	fn ctx(
		self,
		message: impl Into<String>,
	) -> anyhow::Result<T> {
		let location = Location::caller();

		self.map_err(|anyhow_error| {
			new_ctx(Some(message.into()), location, anyhow_error.into())
		})
	}

	#[track_caller]
	fn ctx_with<F, S>(
		self,
		f: F,
	) -> anyhow::Result<T>
	where
		F: FnOnce() -> S,
		S: Into<String>,
	{
		let location = Location::caller();

		self.map_err(|anyhow_error| {
			new_ctx(Some(f().into()), location, anyhow_error.into())
		})
	}

	#[track_caller]
	fn here(
		self,
	) -> anyhow::Result<T> {
		let location = Location::caller();
		self.map_err(|anyhow_error| new_ctx(None, location, anyhow_error.into()))
	}
}