polkavm 0.29.1

A fast and secure RISC-V based virtual machine
Documentation
use alloc::string::{String, ToString};
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<&'static str> for Error {
    #[cold]
    fn from(message: &'static str) -> Self {
        Error(ErrorKind::Static(message))
    }
}

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))
    }
}

if_compiler_is_supported! {
    #[cfg(target_os = "linux")]
    impl From<polkavm_linux_raw::Error> for Error {
        #[cold]
        fn from(error: polkavm_linux_raw::Error) -> Self {
            Self(ErrorKind::Owned(error.to_string()))
        }
    }

    #[cfg(feature = "generic-sandbox")]
    use crate::sandbox::generic;

    #[cfg(feature = "generic-sandbox")]
    impl From<generic::Error> for Error {
        #[cold]
        fn from(error: generic::Error) -> Self {
            Self(ErrorKind::Owned(error.to_string()))
        }
    }
}

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))
    }
}

if_compiler_is_supported! {
    impl Error {
        #[cold]
        pub(crate) fn context(self, message: impl core::fmt::Display) -> Self {
            use alloc::format;

            let string = match self.0 {
                ErrorKind::Owned(buffer) => format!("{}: {}", message, buffer),
                error => format!("{}: {}", message, Error(error)),
            };

            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 core::error::Error for Error {}

impl From<Error> for String {
    fn from(error: Error) -> String {
        error.to_string()
    }
}