//! `wasi_common::Error` is now `anyhow::Error`. //! //! Snapshots (right now only `wasi_common::snapshots::preview_1`) contains //! all of the logic for transforming an `Error` into the snapshot's own //! `Errno`. They may do so by downcasting the error into any of: //! * `std::io::Error` - these are thrown by `std`, `cap_std`, etc for most of //! the operations WASI is concerned with. //! * `wasi_common::ErrorKind` - these are a subset of the Errnos, and are //! constructed directly by wasi-common or an impl rather than coming from the //! OS or some library which doesn't know about WASI. //! * `wiggle::GuestError` //! * `std::num::TryFromIntError` //! * `std::str::Utf8Error` //! and then applying specialized logic to translate each of those into //! `Errno`s. //! //! The `wasi_common::ErrorExt` trait provides human-friendly constructors for //! the `wasi_common::ErrorKind` variants . //! //! If you throw an error that does not downcast to one of those, it will turn //! into a `wiggle::Trap` and terminate execution. //! //! The real value of using `anyhow::Error` here is being able to use //! `anyhow::Result::context` to aid in debugging of errors. pub use anyhow::Error; /// Internal error type for the `wasi-common` crate. /// Contains variants of the WASI `$errno` type are added according to what is actually used internally by /// the crate. Not all values are represented presently. #[derive(Debug, thiserror::Error)] pub enum ErrorKind { /// Errno::Noent: No such file or directory #[error("Noent: No such file or directory")] Noent, /// Errno::TooBig: Argument list too long #[error("TooBig: Argument list too long")] TooBig, /// Errno::Badf: Bad file descriptor #[error("Badf: Bad file descriptor")] Badf, /// Errno::Exist: File exists #[error("Exist: File exists")] Exist, /// Errno::Ilseq: Illegal byte sequence #[error("Ilseq: Illegal byte sequence")] Ilseq, /// Errno::Inval: Invalid argument #[error("Inval: Invalid argument")] Inval, /// Errno::Io: I/O error #[error("Io: I/O error")] Io, /// Errno::Nametoolong: Filename too long #[error("Nametoolong: Filename too long")] Nametoolong, /// Errno::Notdir: Not a directory or a symbolic link to a directory. #[error("Notdir: Not a directory or a symbolic link to a directory")] Notdir, /// Errno::Notsup: Not supported, or operation not supported on socket. #[error("Notsup: Not supported, or operation not supported on socket")] Notsup, /// Errno::Overflow: Value too large to be stored in data type. #[error("Overflow: Value too large to be stored in data type")] Overflow, /// Errno::Range: Result too large #[error("Range: Result too large")] Range, /// Errno::Spipe: Invalid seek #[error("Spipe: Invalid seek")] Spipe, /// Errno::NotCapable: Not capable #[error("Not capable")] NotCapable, } pub trait ErrorExt { fn trap(msg: impl Into) -> Self; fn not_found() -> Self; fn too_big() -> Self; fn badf() -> Self; fn exist() -> Self; fn illegal_byte_sequence() -> Self; fn invalid_argument() -> Self; fn io() -> Self; fn name_too_long() -> Self; fn not_dir() -> Self; fn not_supported() -> Self; fn overflow() -> Self; fn range() -> Self; fn seek_pipe() -> Self; fn not_capable() -> Self; } impl ErrorExt for Error { fn trap(msg: impl Into) -> Self { anyhow::anyhow!(msg.into()) } fn not_found() -> Self { ErrorKind::Noent.into() } fn too_big() -> Self { ErrorKind::TooBig.into() } fn badf() -> Self { ErrorKind::Badf.into() } fn exist() -> Self { ErrorKind::Exist.into() } fn illegal_byte_sequence() -> Self { ErrorKind::Ilseq.into() } fn invalid_argument() -> Self { ErrorKind::Inval.into() } fn io() -> Self { ErrorKind::Io.into() } fn name_too_long() -> Self { ErrorKind::Nametoolong.into() } fn not_dir() -> Self { ErrorKind::Notdir.into() } fn not_supported() -> Self { ErrorKind::Notsup.into() } fn overflow() -> Self { ErrorKind::Overflow.into() } fn range() -> Self { ErrorKind::Range.into() } fn seek_pipe() -> Self { ErrorKind::Spipe.into() } fn not_capable() -> Self { ErrorKind::NotCapable.into() } }