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