Skip to main content

Mountain/Error/
CoreError.rs

1//! # Core Error Types (local, dead-code stack)
2//!
3//! Base building blocks of Mountain's local error taxonomy. Five
4//! per-domain sibling modules (`IPCError`, `FileSystemError`,
5//! `ConfigurationError`, `ProviderError`, `ServiceError`) wrap an
6//! `ErrorContext` and converge on `MountainError` via a `From` impl.
7//!
8//! TODO atomic split: this file is **NOT** atomized into one-symbol-per-
9//! file because the five sibling modules each construct
10//! `ErrorContext { context: ..., severity: ..., kind: ... }` literally,
11//! and call `.with_kind` / `.with_severity` / `.with_operation`. Splitting
12//! `ErrorContext`/`MountainError` into `Struct`-renamed atoms would
13//! require renaming every field+method across ~700 lines of dead code.
14//! Defer until the whole stack is either deleted or migrated to
15//! `CommonLibrary::Error::CommonError`.
16//!
17//! TODO: zero callers as of 2026-05-02 - superseded by
18//! `CommonLibrary::Error::CommonError`.
19
20use std::{error::Error as StdError, fmt};
21
22use serde::{Deserialize, Serialize};
23
24/// Severity level of an error
25#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
26pub enum ErrorSeverity {
27	Info = 0,
28	Warning = 1,
29	Error = 2,
30	Critical = 3,
31}
32
33impl fmt::Display for ErrorSeverity {
34	fn fmt(&self, f:&mut fmt::Formatter<'_>) -> fmt::Result {
35		match self {
36			ErrorSeverity::Info => write!(f, "Info"),
37			ErrorSeverity::Warning => write!(f, "Warning"),
38			ErrorSeverity::Error => write!(f, "Error"),
39			ErrorSeverity::Critical => write!(f, "Critical"),
40		}
41	}
42}
43
44/// Top-level error category.
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
46pub enum ErrorKind {
47	IPC,
48	FileSystem,
49	Configuration,
50	Service,
51	Provider,
52	Other,
53}
54
55impl fmt::Display for ErrorKind {
56	fn fmt(&self, f:&mut fmt::Formatter<'_>) -> fmt::Result {
57		match self {
58			ErrorKind::IPC => write!(f, "IPC"),
59			ErrorKind::FileSystem => write!(f, "FileSystem"),
60			ErrorKind::Configuration => write!(f, "Configuration"),
61			ErrorKind::Service => write!(f, "Service"),
62			ErrorKind::Provider => write!(f, "Provider"),
63			ErrorKind::Other => write!(f, "Other"),
64		}
65	}
66}
67
68/// Companion metadata attached to every `MountainError`.
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct ErrorContext {
71	pub message:String,
72	pub kind:ErrorKind,
73	pub severity:ErrorSeverity,
74	pub operation:Option<String>,
75	pub component:Option<String>,
76}
77
78impl ErrorContext {
79	pub fn new(message:impl Into<String>) -> Self {
80		Self {
81			message:message.into(),
82			kind:ErrorKind::Other,
83			severity:ErrorSeverity::Error,
84			operation:None,
85			component:None,
86		}
87	}
88
89	pub fn with_kind(mut self, kind:ErrorKind) -> Self {
90		self.kind = kind;
91		self
92	}
93
94	pub fn with_severity(mut self, severity:ErrorSeverity) -> Self {
95		self.severity = severity;
96		self
97	}
98
99	pub fn with_operation(mut self, operation:impl Into<String>) -> Self {
100		self.operation = Some(operation.into());
101		self
102	}
103
104	pub fn with_component(mut self, component:impl Into<String>) -> Self {
105		self.component = Some(component.into());
106		self
107	}
108}
109
110impl fmt::Display for ErrorContext {
111	fn fmt(&self, f:&mut fmt::Formatter<'_>) -> fmt::Result {
112		write!(f, "[{}][{}] {}", self.kind, self.severity, self.message)
113	}
114}
115
116/// Base Mountain error type.
117#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct MountainError {
119	pub context:ErrorContext,
120	pub source:Option<String>,
121	pub stack_trace:Option<String>,
122}
123
124impl MountainError {
125	pub fn new(context:ErrorContext) -> Self { Self { context, source:None, stack_trace:None } }
126
127	pub fn with_source(mut self, source:impl Into<String>) -> Self {
128		self.source = Some(source.into());
129		self
130	}
131
132	pub fn with_stack_trace(mut self, stack_trace:impl Into<String>) -> Self {
133		self.stack_trace = Some(stack_trace.into());
134		self
135	}
136
137	pub fn message(&self) -> &str { &self.context.message }
138
139	pub fn kind(&self) -> ErrorKind { self.context.kind }
140
141	pub fn severity(&self) -> ErrorSeverity { self.context.severity }
142
143	pub fn is_critical(&self) -> bool { self.context.severity == ErrorSeverity::Critical }
144}
145
146impl fmt::Display for MountainError {
147	fn fmt(&self, f:&mut fmt::Formatter<'_>) -> fmt::Result {
148		write!(f, "{}", self.context)?;
149		if let Some(source) = &self.source {
150			write!(f, " ({})", source)?;
151		}
152		Ok(())
153	}
154}
155
156impl StdError for MountainError {}
157
158impl From<ErrorContext> for MountainError {
159	fn from(context:ErrorContext) -> Self { Self::new(context) }
160}
161
162/// Result type alias for Mountain operations.
163pub type Result<T> = std::result::Result<T, MountainError>;