syntaxis/shared/templates/rust-core/error.rs.template

117 lines
3.2 KiB
Plaintext
Raw Permalink Normal View History

//! Error handling for {{TOOL_NAME}}
//!
//! Uses canonical error struct pattern following Microsoft Pragmatic Rust Guidelines.
use std::error::Error;
use std::fmt;
use std::backtrace::Backtrace;
/// {{TOOL_NAME}} error result type
pub type Result<T> = std::result::Result<T, {{ToolName}}Error>;
/// {{TOOL_NAME}} error kinds
#[derive(Debug)]
#[non_exhaustive]
pub enum {{ToolName}}ErrorKind {
/// Configuration error
ConfigError(String),
/// I/O error
IoError(String),
/// Validation error
ValidationError(String),
/// Database error
DatabaseError(String),
/// Unknown error
Unknown(String),
}
impl fmt::Display for {{ToolName}}ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::ConfigError(msg) => write!(f, "Configuration error: {}", msg),
Self::IoError(msg) => write!(f, "I/O error: {}", msg),
Self::ValidationError(msg) => write!(f, "Validation error: {}", msg),
Self::DatabaseError(msg) => write!(f, "Database error: {}", msg),
Self::Unknown(msg) => write!(f, "Unknown error: {}", msg),
}
}
}
/// {{TOOL_NAME}} error with context
pub struct {{ToolName}}Error {
/// Error kind
pub kind: {{ToolName}}ErrorKind,
/// Context about what was happening
pub context: String,
/// Root cause if available
pub source: Option<Box<dyn Error + Send + Sync>>,
/// Backtrace for debugging
pub backtrace: Backtrace,
}
impl {{ToolName}}Error {
/// Create a new error with kind and context
pub fn new(kind: {{ToolName}}ErrorKind, context: impl Into<String>) -> Self {
Self {
kind,
context: context.into(),
source: None,
backtrace: Backtrace::capture(),
}
}
/// Add source error
pub fn with_source(mut self, source: Box<dyn Error + Send + Sync>) -> Self {
self.source = Some(source);
self
}
}
impl fmt::Debug for {{ToolName}}Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("{{ToolName}}Error")
.field("kind", &self.kind)
.field("context", &self.context)
.field("source", &self.source)
.finish()
}
}
impl fmt::Display for {{ToolName}}Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}: {}", self.kind, self.context)
}
}
impl Error for {{ToolName}}Error {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.source.as_ref().map(|e| e.as_ref() as &(dyn Error + 'static))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_creation() {
let err = {{ToolName}}Error::new(
{{ToolName}}ErrorKind::ConfigError("test".into()),
"test context",
);
assert_eq!(err.context, "test context");
assert!(err.source.is_none());
}
#[test]
fn test_error_display() {
let err = {{ToolName}}Error::new(
{{ToolName}}ErrorKind::ValidationError("invalid input".into()),
"during validation",
);
let msg = format!("{}", err);
assert!(msg.contains("invalid input"));
assert!(msg.contains("during validation"));
}
}