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