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
use polkavm_common::program::ProgramParseError;

macro_rules! bail {
    ($($arg:expr),* $(,)?) => {
        return Err(Error::from_display(format_args!($($arg),*)))
    }
}

macro_rules! bail_static {
    ($arg:expr) => {
        return Err(Error::from_static_str($arg))
    };
}

pub(crate) use bail;
pub(crate) use bail_static;

#[derive(Debug)]
enum ErrorKind {
    Owned(String),
    Static(&'static str),
    ProgramParseError(ProgramParseError),
}

#[derive(Debug)]
#[repr(transparent)]
pub struct Error(ErrorKind);

impl From<String> for Error {
    #[cold]
    fn from(string: String) -> Self {
        Error(ErrorKind::Owned(string))
    }
}

impl From<ProgramParseError> for Error {
    #[cold]
    fn from(error: ProgramParseError) -> Self {
        Self(ErrorKind::ProgramParseError(error))
    }
}

impl Error {
    #[cold]
    pub(crate) fn from_display(message: impl core::fmt::Display) -> Self {
        Error(ErrorKind::Owned(message.to_string()))
    }

    #[cold]
    pub(crate) fn from_static_str(message: &'static str) -> Self {
        Error(ErrorKind::Static(message))
    }

    #[cold]
    pub(crate) fn from_execution_error<E>(error: ExecutionError<E>) -> Self
    where
        E: core::fmt::Display,
    {
        match error {
            ExecutionError::Error(error) => Error::from_display(error),
            ExecutionError::Trap(_) => Error::from_display("unexpected trap"),
            ExecutionError::OutOfGas => Error::from_display("unexpected out-of-gas"),
        }
    }

    #[cold]
    pub(crate) fn context(self, message: impl core::fmt::Display) -> Self {
        let string = match self.0 {
            ErrorKind::Owned(mut buffer) => {
                use core::fmt::Write;
                let _ = write!(&mut buffer, ": {}", message);
                buffer
            }
            error => format!("{}: {}", Error(error), message),
        };

        Error(ErrorKind::Owned(string))
    }
}

impl core::fmt::Display for Error {
    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
        let message = match &self.0 {
            ErrorKind::Owned(message) => message.as_str(),
            ErrorKind::Static(message) => message,
            ErrorKind::ProgramParseError(error) => return error.fmt(fmt),
        };

        fmt.write_str(message)
    }
}

impl std::error::Error for Error {}

pub type ExecutionError<T = Error> = polkavm_common::error::ExecutionError<T>;