1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! `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::{Context, 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::WouldBlk: Would block
    #[error("WouldBlk: Would block")]
    WouldBlk,
    /// 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::Perm: Permission denied
    #[error("Permission denied")]
    Perm,
    /// Errno::NotCapable: Not capable
    #[error("Not capable")]
    NotCapable,
}

pub trait ErrorExt {
    fn trap(msg: impl Into<String>) -> 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 perm() -> Self;
}

impl ErrorExt for Error {
    fn trap(msg: impl Into<String>) -> 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 perm() -> Self {
        ErrorKind::Perm.into()
    }
}