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
//! Wolfram LibraryLink errors.

use std::fmt::{self, Display, Formatter};
use sys::errcode_t;

/// The error type for Wolfram LibraryLink.
///
/// **see also**: [Library Structure and Life Cycle: Errors](https://reference.wolfram.com/language/LibraryLink/tutorial/LibraryStructure.html#59563264).
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Error(Repr);

#[derive(Debug, Eq, PartialEq, Clone, Copy)]
enum Repr {
    Simple(ErrorKind),
    Raw(errcode_t),
}

/// A list specifying general categories of Wolfram LibraryLink error.
///
/// It is used with the [`Error`] type.
///
/// [`Error`]: ./struct.Error.html
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum ErrorKind {
    /// Unexpected type encountered.
    TypeError = 1,
    /// Unexpected rank encountered.
    RankError,
    /// Inconsistent dimensions encountered.
    DimensionError,
    /// Error in numerical computation.
    NumericalError,
    /// Problem allocating memory.
    MemoryError,
    /// Generic error from a function.
    FunctionError,
    /// Incompatible version.
    VersionError,
}

impl Error {
    /// Creates a new instance of an `Error` from a raw error code.
    #[inline]
    pub fn from_raw_error(code: errcode_t) -> Option<Self> {
        if code == sys::LIBRARY_NO_ERROR {
            None
        } else {
            Some(Error(Repr::Raw(code)))
        }
    }

    /// Returns the raw error code that this error represents.
    #[inline]
    pub fn to_raw_error(&self) -> errcode_t {
        match self.0 {
            Repr::Simple(kind) => kind.to_raw_error(),
            Repr::Raw(code) => code,
        }
    }

    /// Returns the corresponding [`ErrorKind`] for this error (if any).
    ///
    /// [`ErrorKind`]: ./enum.ErrorKind.html
    #[inline]
    pub fn kind(&self) -> Option<ErrorKind> {
        match self.0 {
            Repr::Simple(kind) => Some(kind),
            Repr::Raw(code) => ErrorKind::from_raw_error(code),
        }
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        use Repr::*;
        match self.0 {
            Simple(kind) => write!(f, "{}", kind),
            Raw(code) => {
                if let Some(kind) = ErrorKind::from_raw_error(code) {
                    write!(f, "{}", kind)
                } else {
                    write!(f, "unknown error code: {}", code)
                }
            }
        }
    }
}

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

impl From<ErrorKind> for Error {
    #[inline]
    fn from(e: ErrorKind) -> Self {
        Error(Repr::Simple(e))
    }
}

impl ErrorKind {
    #[inline]
    pub(crate) fn to_raw_error(&self) -> errcode_t {
        use ErrorKind::*;
        match *self {
            TypeError => sys::LIBRARY_TYPE_ERROR,
            RankError => sys::LIBRARY_RANK_ERROR,
            DimensionError => sys::LIBRARY_DIMENSION_ERROR,
            NumericalError => sys::LIBRARY_NUMERICAL_ERROR,
            MemoryError => sys::LIBRARY_MEMORY_ERROR,
            FunctionError => sys::LIBRARY_FUNCTION_ERROR,
            VersionError => sys::LIBRARY_VERSION_ERROR,
        }
    }

    #[inline]
    pub(crate) fn from_raw_error(code: errcode_t) -> Option<Self> {
        use ErrorKind::*;
        match code {
            sys::LIBRARY_NO_ERROR => unreachable!(),
            sys::LIBRARY_TYPE_ERROR => Some(TypeError),
            sys::LIBRARY_RANK_ERROR => Some(RankError),
            sys::LIBRARY_DIMENSION_ERROR => Some(DimensionError),
            sys::LIBRARY_NUMERICAL_ERROR => Some(NumericalError),
            sys::LIBRARY_MEMORY_ERROR => Some(MemoryError),
            sys::LIBRARY_FUNCTION_ERROR => Some(FunctionError),
            sys::LIBRARY_VERSION_ERROR => Some(VersionError),
            _ => None,
        }
    }
}

impl Display for ErrorKind {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        use ErrorKind::*;
        match *self {
            TypeError => write!(f, "unexpected type encountered"),
            RankError => write!(f, "unexpected rank encountered "),
            DimensionError => write!(f, "inconsistent dimensions encountered"),
            NumericalError => write!(f, "error in numerical computation"),
            MemoryError => write!(f, "problem allocating memory"),
            FunctionError => write!(f, "generic error from a function"),
            VersionError => write!(f, "incompatible version"),
        }
    }
}