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
use crate::{AccessError, Integer, Panic, ReflectValueType, ValueTypeInfo, VmError, VmErrorKind};
use thiserror::Error;
/// Errors raised by the execution of the virtual machine.
#[derive(Error, Debug)]
#[error(transparent)]
pub struct ValueError {
    kind: Box<ValueErrorKind>,
}

impl ValueError {
    /// Inspect the value error kind.
    pub fn kind(&self) -> &ValueErrorKind {
        &self.kind
    }

    /// Immediately convert value error into VmError for smuggled variants.
    pub fn unsmuggle_vm_error(self) -> Result<VmError, Self> {
        match *self.kind {
            ValueErrorKind::Panic { reason } => Ok(VmError::from(VmErrorKind::Panic { reason })),
            ValueErrorKind::VmError { error } => Ok(error),
            kind => Err(Self {
                kind: Box::new(kind),
            }),
        }
    }
}

impl<E> From<E> for ValueError
where
    ValueErrorKind: From<E>,
{
    fn from(err: E) -> Self {
        Self {
            kind: Box::new(ValueErrorKind::from(err)),
        }
    }
}

/// Value raised when interacting with a value.
#[derive(Debug, Error)]
pub enum ValueErrorKind {
    /// The virtual machine panicked for a specific reason.
    #[error("panicked `{reason}`")]
    Panic {
        /// The reason for the panic.
        reason: Panic,
    },
    /// A wrapped virtual machine error.
    #[error("{error}")]
    VmError {
        /// The source error.
        #[source]
        error: VmError,
    },
    /// Trying to access an inaccessible reference.
    #[error("failed to access value: {error}")]
    AccessError {
        /// Source error.
        #[from]
        error: AccessError,
    },
    /// Error raised when we expected one type, but got another.
    #[error("expected `{expected}`, but found `{actual}`")]
    Expected {
        /// The expected value type info.
        expected: ValueTypeInfo,
        /// The actual type found.
        actual: ValueTypeInfo,
    },
    /// Error raised when we expected a value.
    #[error("expected `Any` type, but found `{actual}`")]
    ExpectedAny {
        /// The actual type observed instead.
        actual: ValueTypeInfo,
    },
    /// Failure to convert a number into an integer.
    #[error("failed to convert value `{from}` to integer `{to}`")]
    ValueToIntegerCoercionError {
        /// Number we tried to convert from.
        from: Integer,
        /// Number type we tried to convert to.
        to: &'static str,
    },
    /// Failure to convert an integer into a value.
    #[error("failed to convert integer `{from}` to value `{to}`")]
    IntegerToValueCoercionError {
        /// Number we tried to convert from.
        from: Integer,
        /// Number type we tried to convert to.
        to: &'static str,
    },
    /// Error raised when we expected an tuple of the given length.
    #[error("expected a tuple of length `{expected}`, but found one with length `{actual}`")]
    ExpectedTupleLength {
        /// The actual length observed.
        actual: usize,
        /// The expected tuple length.
        expected: usize,
    },
    /// Internal error that happens when we run out of items in a list.
    #[error("unexpectedly ran out of items to iterate over")]
    IterationError,
}

impl ValueError {
    /// Construct an expected error.
    pub fn expected<T>(actual: ValueTypeInfo) -> Self
    where
        T: ReflectValueType,
    {
        Self::from(ValueErrorKind::Expected {
            expected: T::value_type_info(),
            actual,
        })
    }

    /// Construct an expected any error.
    pub fn expected_any(actual: ValueTypeInfo) -> Self {
        Self::from(ValueErrorKind::ExpectedAny { actual })
    }
}