1extern crate alloc;
4
5use alloc::boxed::Box;
6use alloc::format;
7use alloc::string::String;
8use core::fmt::{self, Debug, Formatter};
9use core::result::Result as CoreResult;
10use core::{error::Error as CoreError, fmt::Display};
11
12use crate::ast::NodeRef;
13
14#[cfg(feature = "std")]
15use std::backtrace::{Backtrace, BacktraceStatus};
16
17pub type Result<T> = CoreResult<T, Error>;
19
20#[derive(Debug)]
23#[non_exhaustive]
24pub enum CallbackError<E: CoreError + 'static> {
25 Internal(Error),
27
28 Callback(E),
30}
31
32impl<E: CoreError + 'static> Display for CallbackError<E> {
33 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
34 match self {
35 CallbackError::Internal(err) => write!(f, "{}", err),
36 CallbackError::Callback(err) => {
37 write!(f, "{}", err)
38 }
39 }
40 }
41}
42
43impl<E: CoreError + 'static> CoreError for CallbackError<E> {
44 fn source(&self) -> Option<&(dyn CoreError + 'static)> {
45 match self {
46 CallbackError::Internal(err) => Some(err),
47 CallbackError::Callback(err) => Some(err),
48 }
49 }
50}
51
52#[non_exhaustive]
54pub enum Error {
55 InvalidNodeRef {
57 noderef: NodeRef,
58 description: String,
59 #[cfg(feature = "std")]
60 backtrace: Backtrace,
61 },
62 InvalidNodeOperation {
64 message: String,
65 description: String,
66 #[cfg(feature = "std")]
67 backtrace: Backtrace,
68 },
69 Io {
71 message: String,
72 description: String,
73 source: Option<Box<dyn CoreError + 'static>>,
74 #[cfg(feature = "std")]
75 backtrace: Backtrace,
76 },
77}
78
79impl Error {
80 pub fn invalid_node_ref(node_ref: NodeRef) -> Self {
82 Error::InvalidNodeRef {
83 noderef: node_ref,
84 description: format!("invalid node reference: {}", node_ref),
85 #[cfg(feature = "std")]
86 backtrace: Backtrace::capture(),
87 }
88 }
89
90 pub fn invalid_node_operation(message: String) -> Self {
92 Error::InvalidNodeOperation {
93 message: message.clone(),
94 description: format!("invalid operation: {}", message),
95 #[cfg(feature = "std")]
96 backtrace: Backtrace::capture(),
97 }
98 }
99
100 pub fn io<S>(m: S, source: Option<Box<dyn CoreError + 'static>>) -> Self
102 where
103 S: Into<String>,
104 {
105 let message = m.into();
106 Error::Io {
107 message: message.clone(),
108 description: format!("io error: {}", message),
109 source,
110 #[cfg(feature = "std")]
111 backtrace: Backtrace::capture(),
112 }
113 }
114
115 #[cfg(feature = "std")]
118 pub fn backtrace(&self) -> Option<&Backtrace> {
119 match self {
120 Error::InvalidNodeRef { backtrace, .. } => Some(backtrace),
121 Error::InvalidNodeOperation { backtrace, .. } => Some(backtrace),
122 Error::Io { backtrace, .. } => Some(backtrace),
123 }
124 }
125}
126
127impl Display for Error {
128 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
129 match self {
130 Error::InvalidNodeRef { description, .. } => write!(f, "{}", description),
131 Error::InvalidNodeOperation { description, .. } => write!(f, "{}", description),
132 Error::Io { description, .. } => write!(f, "{}", description),
133 }
134 }
135}
136
137impl Debug for Error {
138 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
139 match self {
140 Error::InvalidNodeRef {
141 description,
142 #[cfg(feature = "std")]
143 backtrace,
144 ..
145 } => {
146 write!(f, "{}", description)?;
147 #[cfg(feature = "std")]
148 {
149 write!(f, "{}", format_backtrace(backtrace))?;
150 }
151 }
152 Error::InvalidNodeOperation {
153 description,
154 #[cfg(feature = "std")]
155 backtrace,
156 ..
157 } => {
158 write!(f, "{}", description)?;
159 #[cfg(feature = "std")]
160 {
161 write!(f, "{}", format_backtrace(backtrace))?;
162 }
163 }
164 Error::Io {
165 description,
166 #[cfg(feature = "std")]
167 backtrace,
168 ..
169 } => {
170 write!(f, "{}", description)?;
171 #[cfg(feature = "std")]
172 {
173 write!(f, "{}", format_backtrace(backtrace))?;
174 }
175 }
176 }
177 if let Some(source) = self.source() {
178 writeln!(f, "Caused by: {:?}", source)?;
179 }
180 Ok(())
181 }
182}
183
184impl CoreError for Error {
185 fn source(&self) -> Option<&(dyn CoreError + 'static)> {
186 {
187 match self {
188 Error::Io { source, .. } => source.as_deref(),
189 _ => None,
190 }
191 }
192 }
193}
194
195#[cfg(feature = "std")]
196fn format_backtrace(backtrace: &Backtrace) -> String {
197 match backtrace.status() {
198 BacktraceStatus::Captured => format!("\nstack backtrace:\n{}", backtrace),
199 _ => String::new(),
200 }
201}