1use std::error::Error as StdError;
2use std::fmt;
3use std::io::Error as IoError;
4use std::net::AddrParseError;
5use std::result::Result as StdResult;
6use std::str::Utf8Error;
7use std::string::String as StdString;
8use std::sync::Arc;
9
10use crate::private::Sealed;
11
12#[cfg(feature = "error-send")]
13type DynStdError = dyn StdError + Send + Sync;
14
15#[cfg(not(feature = "error-send"))]
16type DynStdError = dyn StdError;
17
18#[derive(Debug, Clone)]
20#[non_exhaustive]
21pub enum Error {
22 SyntaxError {
24 message: StdString,
26 incomplete_input: bool,
31 },
32 RuntimeError(StdString),
38 MemoryError(StdString),
43 #[cfg(any(feature = "lua53", feature = "lua52", doc))]
47 #[cfg_attr(docsrs, doc(cfg(any(feature = "lua53", feature = "lua52"))))]
48 GarbageCollectorError(StdString),
49 SafetyError(StdString),
51 MemoryControlNotAvailable,
56 RecursiveMutCallback,
60 CallbackDestructed,
66 StackError,
73 BindError,
77 BadArgument {
82 to: Option<StdString>,
84 pos: usize,
86 name: Option<StdString>,
88 cause: Arc<Error>,
90 },
91 ToLuaConversionError {
93 from: String,
95 to: &'static str,
97 message: Option<StdString>,
99 },
100 FromLuaConversionError {
102 from: &'static str,
104 to: String,
106 message: Option<StdString>,
108 },
109 CoroutineUnresumable,
120 UserDataTypeMismatch,
129 UserDataDestructed,
136 UserDataBorrowError,
145 UserDataBorrowMutError,
154 MetaMethodRestricted(StdString),
158 MetaMethodTypeError {
162 method: StdString,
164 type_name: &'static str,
166 message: Option<StdString>,
168 },
169 MismatchedRegistryKey,
173 CallbackError {
175 traceback: StdString,
177 cause: Arc<Error>,
179 },
180 PreviouslyResumedPanic,
185 #[cfg(feature = "serde")]
187 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
188 SerializeError(StdString),
189 #[cfg(feature = "serde")]
191 #[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
192 DeserializeError(StdString),
193 ExternalError(Arc<DynStdError>),
201 WithContext {
203 context: StdString,
205 cause: Arc<Error>,
207 },
208}
209
210pub type Result<T> = StdResult<T, Error>;
212
213#[cfg(not(tarpaulin_include))]
214impl fmt::Display for Error {
215 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
216 match self {
217 Error::SyntaxError { message, .. } => write!(fmt, "syntax error: {message}"),
218 Error::RuntimeError(msg) => write!(fmt, "runtime error: {msg}"),
219 Error::MemoryError(msg) => {
220 write!(fmt, "memory error: {msg}")
221 }
222 #[cfg(any(feature = "lua53", feature = "lua52"))]
223 Error::GarbageCollectorError(msg) => {
224 write!(fmt, "garbage collector error: {msg}")
225 }
226 Error::SafetyError(msg) => {
227 write!(fmt, "safety error: {msg}")
228 },
229 Error::MemoryControlNotAvailable => {
230 write!(fmt, "memory control is not available")
231 }
232 Error::RecursiveMutCallback => write!(fmt, "mutable callback called recursively"),
233 Error::CallbackDestructed => write!(
234 fmt,
235 "a destructed callback or destructed userdata method was called"
236 ),
237 Error::StackError => write!(
238 fmt,
239 "out of Lua stack, too many arguments to a Lua function or too many return values from a callback"
240 ),
241 Error::BindError => write!(
242 fmt,
243 "too many arguments to Function::bind"
244 ),
245 Error::BadArgument { to, pos, name, cause } => {
246 if let Some(name) = name {
247 write!(fmt, "bad argument `{name}`")?;
248 } else {
249 write!(fmt, "bad argument #{pos}")?;
250 }
251 if let Some(to) = to {
252 write!(fmt, " to `{to}`")?;
253 }
254 write!(fmt, ": {cause}")
255 },
256 Error::ToLuaConversionError { from, to, message } => {
257 write!(fmt, "error converting {from} to Lua {to}")?;
258 match message {
259 None => Ok(()),
260 Some(message) => write!(fmt, " ({message})"),
261 }
262 }
263 Error::FromLuaConversionError { from, to, message } => {
264 write!(fmt, "error converting Lua {from} to {to}")?;
265 match message {
266 None => Ok(()),
267 Some(message) => write!(fmt, " ({message})"),
268 }
269 }
270 Error::CoroutineUnresumable => write!(fmt, "coroutine is non-resumable"),
271 Error::UserDataTypeMismatch => write!(fmt, "userdata is not expected type"),
272 Error::UserDataDestructed => write!(fmt, "userdata has been destructed"),
273 Error::UserDataBorrowError => write!(fmt, "error borrowing userdata"),
274 Error::UserDataBorrowMutError => write!(fmt, "error mutably borrowing userdata"),
275 Error::MetaMethodRestricted(method) => write!(fmt, "metamethod {method} is restricted"),
276 Error::MetaMethodTypeError { method, type_name, message } => {
277 write!(fmt, "metamethod {method} has unsupported type {type_name}")?;
278 match message {
279 None => Ok(()),
280 Some(message) => write!(fmt, " ({message})"),
281 }
282 }
283 Error::MismatchedRegistryKey => {
284 write!(fmt, "RegistryKey used from different Lua state")
285 }
286 Error::CallbackError { cause, traceback } => {
287 let (mut cause, mut full_traceback) = (cause, None);
289 while let Error::CallbackError { cause: cause2, traceback: traceback2 } = &**cause {
290 cause = cause2;
291 full_traceback = Some(traceback2);
292 }
293 writeln!(fmt, "{cause}")?;
294 if let Some(full_traceback) = full_traceback {
295 let traceback = traceback.trim_start_matches("stack traceback:");
296 let traceback = traceback.trim_start().trim_end();
297 if let Some(pos) = full_traceback.find(traceback) {
299 write!(fmt, "{}", &full_traceback[..pos])?;
300 writeln!(fmt, ">{}", &full_traceback[pos..].trim_end())?;
301 } else {
302 writeln!(fmt, "{}", full_traceback.trim_end())?;
303 }
304 } else {
305 writeln!(fmt, "{}", traceback.trim_end())?;
306 }
307 Ok(())
308 }
309 Error::PreviouslyResumedPanic => {
310 write!(fmt, "previously resumed panic returned again")
311 }
312 #[cfg(feature = "serde")]
313 Error::SerializeError(err) => {
314 write!(fmt, "serialize error: {err}")
315 },
316 #[cfg(feature = "serde")]
317 Error::DeserializeError(err) => {
318 write!(fmt, "deserialize error: {err}")
319 },
320 Error::ExternalError(err) => err.fmt(fmt),
321 Error::WithContext { context, cause } => {
322 writeln!(fmt, "{context}")?;
323 write!(fmt, "{cause}")
324 }
325 }
326 }
327}
328
329impl StdError for Error {
330 fn source(&self) -> Option<&(dyn StdError + 'static)> {
331 match self {
332 Error::CallbackError { .. } => None,
338 Error::ExternalError(err) => err.source(),
339 Error::WithContext { cause, .. } => Self::source(cause),
340 _ => None,
341 }
342 }
343}
344
345impl Error {
346 #[inline]
348 pub fn runtime<S: fmt::Display>(message: S) -> Self {
349 Error::RuntimeError(message.to_string())
350 }
351
352 #[inline]
354 pub fn external<T: Into<Box<DynStdError>>>(err: T) -> Self {
355 Error::ExternalError(err.into().into())
356 }
357
358 pub fn downcast_ref<T>(&self) -> Option<&T>
360 where
361 T: StdError + 'static,
362 {
363 match self {
364 Error::ExternalError(err) => err.downcast_ref(),
365 Error::WithContext { cause, .. } => Self::downcast_ref(cause),
366 _ => None,
367 }
368 }
369
370 pub fn chain(&self) -> impl Iterator<Item = &(dyn StdError + 'static)> {
372 Chain {
373 root: self,
374 current: None,
375 }
376 }
377
378 #[doc(hidden)]
380 pub fn parent(&self) -> Option<&Error> {
381 match self {
382 Error::CallbackError { cause, .. } => Some(cause.as_ref()),
383 Error::WithContext { cause, .. } => Some(cause.as_ref()),
384 _ => None,
385 }
386 }
387
388 pub(crate) fn bad_self_argument(to: &str, cause: Error) -> Self {
389 Error::BadArgument {
390 to: Some(to.to_string()),
391 pos: 1,
392 name: Some("self".to_string()),
393 cause: Arc::new(cause),
394 }
395 }
396
397 pub(crate) fn from_lua_conversion(
398 from: &'static str,
399 to: impl ToString,
400 message: impl Into<Option<String>>,
401 ) -> Self {
402 Error::FromLuaConversionError {
403 from,
404 to: to.to_string(),
405 message: message.into(),
406 }
407 }
408}
409
410pub trait ExternalError {
412 fn into_lua_err(self) -> Error;
413}
414
415impl<E: Into<Box<DynStdError>>> ExternalError for E {
416 fn into_lua_err(self) -> Error {
417 Error::external(self)
418 }
419}
420
421pub trait ExternalResult<T> {
423 fn into_lua_err(self) -> Result<T>;
424}
425
426impl<T, E> ExternalResult<T> for StdResult<T, E>
427where
428 E: ExternalError,
429{
430 fn into_lua_err(self) -> Result<T> {
431 self.map_err(|e| e.into_lua_err())
432 }
433}
434
435pub trait ErrorContext: Sealed {
437 fn context<C: fmt::Display>(self, context: C) -> Self;
439
440 fn with_context<C: fmt::Display>(self, f: impl FnOnce(&Error) -> C) -> Self;
443}
444
445impl ErrorContext for Error {
446 fn context<C: fmt::Display>(self, context: C) -> Self {
447 let context = context.to_string();
448 match self {
449 Error::WithContext { cause, .. } => Error::WithContext { context, cause },
450 _ => Error::WithContext {
451 context,
452 cause: Arc::new(self),
453 },
454 }
455 }
456
457 fn with_context<C: fmt::Display>(self, f: impl FnOnce(&Error) -> C) -> Self {
458 let context = f(&self).to_string();
459 match self {
460 Error::WithContext { cause, .. } => Error::WithContext { context, cause },
461 _ => Error::WithContext {
462 context,
463 cause: Arc::new(self),
464 },
465 }
466 }
467}
468
469impl<T> ErrorContext for Result<T> {
470 fn context<C: fmt::Display>(self, context: C) -> Self {
471 self.map_err(|err| err.context(context))
472 }
473
474 fn with_context<C: fmt::Display>(self, f: impl FnOnce(&Error) -> C) -> Self {
475 self.map_err(|err| err.with_context(f))
476 }
477}
478
479impl From<AddrParseError> for Error {
480 fn from(err: AddrParseError) -> Self {
481 Error::external(err)
482 }
483}
484
485impl From<IoError> for Error {
486 fn from(err: IoError) -> Self {
487 Error::external(err)
488 }
489}
490
491impl From<Utf8Error> for Error {
492 fn from(err: Utf8Error) -> Self {
493 Error::external(err)
494 }
495}
496
497#[cfg(feature = "serde")]
498impl serde::ser::Error for Error {
499 fn custom<T: fmt::Display>(msg: T) -> Self {
500 Self::SerializeError(msg.to_string())
501 }
502}
503
504#[cfg(feature = "serde")]
505impl serde::de::Error for Error {
506 fn custom<T: fmt::Display>(msg: T) -> Self {
507 Self::DeserializeError(msg.to_string())
508 }
509}
510
511#[cfg(feature = "anyhow")]
512impl From<anyhow::Error> for Error {
513 fn from(err: anyhow::Error) -> Self {
514 match err.downcast::<Self>() {
515 Ok(err) => err,
516 Err(err) => Error::external(err),
517 }
518 }
519}
520
521struct Chain<'a> {
522 root: &'a Error,
523 current: Option<&'a (dyn StdError + 'static)>,
524}
525
526impl<'a> Iterator for Chain<'a> {
527 type Item = &'a (dyn StdError + 'static);
528
529 fn next(&mut self) -> Option<Self::Item> {
530 loop {
531 let error: Option<&dyn StdError> = match self.current {
532 None => {
533 self.current = Some(self.root);
534 self.current
535 }
536 Some(current) => match current.downcast_ref::<Error>()? {
537 Error::BadArgument { cause, .. }
538 | Error::CallbackError { cause, .. }
539 | Error::WithContext { cause, .. } => {
540 self.current = Some(&**cause);
541 self.current
542 }
543 Error::ExternalError(err) => {
544 self.current = Some(&**err);
545 self.current
546 }
547 _ => None,
548 },
549 };
550
551 if let Some(Error::ExternalError(_)) = error?.downcast_ref::<Error>() {
554 continue;
555 }
556
557 return self.current;
558 }
559 }
560}
561
562#[cfg(test)]
563mod assertions {
564 use super::*;
565
566 #[cfg(not(feature = "error-send"))]
567 static_assertions::assert_not_impl_any!(Error: Send, Sync);
568 #[cfg(feature = "send")]
569 static_assertions::assert_impl_all!(Error: Send, Sync);
570}