turbo_vision/core/
error.rs1use std::backtrace::Backtrace;
9use std::fmt::{Display, Formatter};
10use std::path::PathBuf;
11
12#[derive(Debug)]
27pub struct TurboVisionError {
28 kind: ErrorKind,
29 backtrace: Backtrace,
30}
31
32#[derive(Debug)]
34#[allow(
35 dead_code,
36 reason = "error kinds reserved for the internal error API, not all constructed yet"
37)]
38pub(crate) enum ErrorKind {
39 Io(std::io::Error),
41
42 TerminalInit(String),
44
45 InvalidInput(String),
47
48 Parse(String),
50
51 FileOperation {
53 path: PathBuf,
54 source: std::io::Error,
55 },
56}
57
58impl TurboVisionError {
59 pub(crate) fn new(kind: ErrorKind) -> Self {
60 Self {
61 kind,
62 backtrace: Backtrace::capture(),
63 }
64 }
65
66 #[allow(dead_code, reason = "reserved error constructor, no call site yet")]
68 pub(crate) fn terminal_init(msg: impl Into<String>) -> Self {
69 Self::new(ErrorKind::TerminalInit(msg.into()))
70 }
71
72 #[allow(dead_code, reason = "reserved error constructor, no call site yet")]
74 pub(crate) fn invalid_input(msg: impl Into<String>) -> Self {
75 Self::new(ErrorKind::InvalidInput(msg.into()))
76 }
77
78 #[allow(dead_code, reason = "reserved error constructor, no call site yet")]
80 pub(crate) fn parse(msg: impl Into<String>) -> Self {
81 Self::new(ErrorKind::Parse(msg.into()))
82 }
83
84 #[allow(dead_code, reason = "reserved error constructor, no call site yet")]
86 pub(crate) fn file_operation(path: impl Into<PathBuf>, source: std::io::Error) -> Self {
87 Self::new(ErrorKind::FileOperation {
88 path: path.into(),
89 source,
90 })
91 }
92
93 pub fn is_io(&self) -> bool {
95 matches!(self.kind, ErrorKind::Io(_))
96 }
97
98 pub fn is_terminal_init(&self) -> bool {
100 matches!(self.kind, ErrorKind::TerminalInit(_))
101 }
102
103 pub fn is_invalid_input(&self) -> bool {
105 matches!(self.kind, ErrorKind::InvalidInput(_))
106 }
107
108 pub fn is_parse(&self) -> bool {
110 matches!(self.kind, ErrorKind::Parse(_))
111 }
112
113 pub fn is_file_operation(&self) -> bool {
115 matches!(self.kind, ErrorKind::FileOperation { .. })
116 }
117
118 pub fn file_path(&self) -> Option<&std::path::Path> {
120 match &self.kind {
121 ErrorKind::FileOperation { path, .. } => Some(path),
122 _ => None,
123 }
124 }
125}
126
127impl Display for TurboVisionError {
128 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
129 match &self.kind {
130 ErrorKind::Io(e) => write!(f, "I/O error: {e}")?,
131 ErrorKind::TerminalInit(msg) => write!(f, "Terminal initialization failed: {msg}")?,
132 ErrorKind::InvalidInput(msg) => write!(f, "Invalid input: {msg}")?,
133 ErrorKind::Parse(msg) => write!(f, "Parse error: {msg}")?,
134 ErrorKind::FileOperation { path, source } => write!(
135 f,
136 "File operation failed for '{}': {}",
137 path.display(),
138 source
139 )?,
140 }
141
142 if self.backtrace.status() == std::backtrace::BacktraceStatus::Captured {
144 write!(f, "\n\nBacktrace:\n{}", self.backtrace)?;
145 }
146
147 Ok(())
148 }
149}
150
151impl std::error::Error for TurboVisionError {
152 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
153 match &self.kind {
154 ErrorKind::Io(e) => Some(e),
155 ErrorKind::FileOperation { source, .. } => Some(source),
156 _ => None,
157 }
158 }
159}
160
161impl From<std::io::Error> for TurboVisionError {
162 fn from(e: std::io::Error) -> Self {
163 Self::new(ErrorKind::Io(e))
164 }
165}
166
167pub type Result<T> = std::result::Result<T, TurboVisionError>;