use displaydoc::Display;
use miette::Diagnostic;
use pace_time::error::PaceTimeErrorKind;
use std::{error::Error, io, path::PathBuf};
use thiserror::Error;
use crate::domain::activity::{Activity, ActivityGuid};
pub type TestResult<T> = Result<T, Box<dyn Error + 'static>>;
pub type PaceResult<T> = Result<T, PaceError>;
pub type PaceOptResult<T> = PaceResult<Option<T>>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UserMessage {
msg: String,
}
impl std::fmt::Display for UserMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.msg)
}
}
impl UserMessage {
pub fn new(msg: impl Into<String>) -> Self {
Self { msg: msg.into() }
}
pub fn display(&self) {
println!("{}", self.msg);
}
}
impl std::ops::DerefMut for UserMessage {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.msg
}
}
impl std::ops::Deref for UserMessage {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.msg
}
}
#[derive(Error, Debug, Diagnostic)]
#[diagnostic(url(docsrs))]
pub struct PaceError(#[from] PaceErrorKind);
impl std::fmt::Display for PaceError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl PaceError {
#[must_use]
pub fn into_inner(self) -> PaceErrorKind {
self.0
}
#[must_use]
pub const fn possible_new_activity_from_resume(&self) -> bool {
matches!(
self.0,
PaceErrorKind::ActivityLog(ActivityLogErrorKind::NoHeldActivityFound(_))
) || matches!(
self.0,
PaceErrorKind::ActivityLog(ActivityLogErrorKind::ActivityAlreadyEnded(_))
) || matches!(
self.0,
PaceErrorKind::ActivityLog(ActivityLogErrorKind::ActivityAlreadyArchived(_))
)
}
}
#[non_exhaustive]
#[derive(Error, Debug, Display)]
pub enum PaceErrorKind {
#[error(transparent)]
StdIo(#[from] std::io::Error),
#[error(transparent)]
SerializationToTomlFailed(#[from] toml::ser::Error),
#[error(transparent)]
DeserializationFromTomlFailed(#[from] toml::de::Error),
#[error(transparent)]
ActivityStore(#[from] ActivityStoreErrorKind),
#[error(transparent)]
ActivityLog(#[from] ActivityLogErrorKind),
#[error(transparent)]
PaceTime(#[from] PaceTimeErrorKind),
#[error(transparent)]
Json(#[from] serde_json::Error),
#[error(transparent)]
ChronoParse(#[from] chrono::ParseError),
#[error(transparent)]
ChronoDurationIsNegative(#[from] chrono::OutOfRangeError),
ConfigFileNotFound {
current_dir: String,
file_name: String,
},
ParentDirNotFound(PathBuf),
DatabaseStorageNotImplemented,
NoPathAvailable,
#[error(transparent)]
Template(#[from] TemplatingErrorKind),
}
#[non_exhaustive]
#[derive(Error, Debug, Display)]
pub enum ActivityLogErrorKind {
NoActivitiesFound,
FailedToReadActivity(ActivityGuid),
NegativeDuration,
NoActivityToHold,
ArcUnwrapFailed,
NoUnfinishedActivities,
NoCacheToSync,
CacheNotAvailable,
ActivityNotFound(ActivityGuid),
ActivityCantBeRemoved(usize),
ActivityIdNotSet,
ActivityIdAlreadyInUse(ActivityGuid),
ActivityIdMismatch(ActivityGuid, ActivityGuid),
ActivityAlreadyHasIntermission(Box<Activity>),
ActivityNotEnded,
NoActiveActivityFound(ActivityGuid),
ActivityAlreadyEnded(ActivityGuid),
ActivityAlreadyArchived(ActivityGuid),
ActiveActivityFound(ActivityGuid),
NoHeldActivityFound(ActivityGuid),
ActivityKindOptionsNotFound(ActivityGuid),
ParentIdNotSet(ActivityGuid),
CategoryNotSet(ActivityGuid),
NoActiveActivityToAdjust,
FailedToGroupByKeywords,
NoEndOptionsFound,
}
#[non_exhaustive]
#[derive(Error, Debug, Display)]
pub enum TemplatingErrorKind {
FailedToGenerateContextFromSerialize(tera::Error),
RenderingToTemplateFailed(tera::Error),
FailedToReadTemplateFile(io::Error),
TemplateFileNotSpecified,
}
#[non_exhaustive]
#[derive(Error, Debug, Display)]
pub enum ActivityStoreErrorKind {
ListActivitiesById,
GroupByDurationRange,
GroupByStartDate,
ListActivitiesWithIntermissions,
GroupByKeywords,
GroupByKind,
ListActivitiesByTimeRange,
PopulatingCache,
ListIntermissionsForActivity(ActivityGuid),
MissingCategoryForActivity(ActivityGuid),
}
trait PaceErrorMarker: Error {}
impl PaceErrorMarker for std::io::Error {}
impl PaceErrorMarker for toml::de::Error {}
impl PaceErrorMarker for toml::ser::Error {}
impl PaceErrorMarker for serde_json::Error {}
#[cfg(feature = "sqlite")]
impl PaceErrorMarker for diesel::ConnectionError {}
impl PaceErrorMarker for chrono::ParseError {}
impl PaceErrorMarker for chrono::OutOfRangeError {}
impl PaceErrorMarker for ActivityLogErrorKind {}
impl PaceErrorMarker for PaceTimeErrorKind {}
impl PaceErrorMarker for ActivityStoreErrorKind {}
impl PaceErrorMarker for TemplatingErrorKind {}
impl<E> From<E> for PaceError
where
E: PaceErrorMarker,
PaceErrorKind: From<E>,
{
fn from(value: E) -> Self {
Self(PaceErrorKind::from(value))
}
}