1use core::{cmp, fmt};
4
5use crate::{
6 alloc::{vec, String, Vec},
7 CallContext, Error, ErrorKind, Function, Number, Value, ValueType,
8};
9
10#[derive(Debug, Clone)]
13pub struct FromValueError {
14 kind: FromValueErrorKind,
15 arg_index: usize,
16 location: Vec<FromValueErrorLocation>,
17}
18
19impl FromValueError {
20 pub(crate) fn invalid_type<T>(expected: ValueType, actual_value: &Value<'_, T>) -> Self {
21 Self {
22 kind: FromValueErrorKind::InvalidType {
23 expected,
24 actual: actual_value.value_type(),
25 },
26 arg_index: 0,
27 location: vec![],
28 }
29 }
30
31 fn add_location(mut self, location: FromValueErrorLocation) -> Self {
32 self.location.push(location);
33 self
34 }
35
36 #[doc(hidden)] pub fn set_arg_index(&mut self, index: usize) {
38 self.arg_index = index;
39 self.location.reverse();
40 }
41
42 pub fn kind(&self) -> &FromValueErrorKind {
44 &self.kind
45 }
46
47 pub fn arg_index(&self) -> usize {
49 self.arg_index
50 }
51
52 pub fn location(&self) -> &[FromValueErrorLocation] {
54 &self.location
55 }
56}
57
58impl fmt::Display for FromValueError {
59 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
60 write!(
61 formatter,
62 "{}. Error location: arg{}",
63 self.kind, self.arg_index
64 )?;
65 for location_element in &self.location {
66 match location_element {
67 FromValueErrorLocation::Tuple { index, .. } => write!(formatter, ".{}", index)?,
68 FromValueErrorLocation::Array { index, .. } => write!(formatter, "[{}]", index)?,
69 }
70 }
71 Ok(())
72 }
73}
74
75#[cfg(feature = "std")]
76impl std::error::Error for FromValueError {}
77
78#[derive(Debug, Clone, PartialEq)]
80#[non_exhaustive]
81pub enum FromValueErrorKind {
82 InvalidType {
84 expected: ValueType,
86 actual: ValueType,
88 },
89}
90
91impl fmt::Display for FromValueErrorKind {
92 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
93 match self {
94 Self::InvalidType { expected, actual } => {
95 write!(formatter, "Cannot convert {} to {}", actual, expected)
96 }
97 }
98 }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq)]
110#[non_exhaustive]
111pub enum FromValueErrorLocation {
112 Tuple {
114 size: usize,
116 index: usize,
118 },
119 Array {
121 size: usize,
123 index: usize,
125 },
126}
127
128pub trait TryFromValue<'a, T>: Sized {
133 fn try_from_value(value: Value<'a, T>) -> Result<Self, FromValueError>;
135}
136
137impl<'a, T: Number> TryFromValue<'a, T> for T {
138 fn try_from_value(value: Value<'a, T>) -> Result<Self, FromValueError> {
139 match value {
140 Value::Prim(number) => Ok(number),
141 _ => Err(FromValueError::invalid_type(ValueType::Prim, &value)),
142 }
143 }
144}
145
146impl<'a, T> TryFromValue<'a, T> for bool {
147 fn try_from_value(value: Value<'a, T>) -> Result<Self, FromValueError> {
148 match value {
149 Value::Bool(flag) => Ok(flag),
150 _ => Err(FromValueError::invalid_type(ValueType::Bool, &value)),
151 }
152 }
153}
154
155impl<'a, T> TryFromValue<'a, T> for Value<'a, T> {
156 fn try_from_value(value: Value<'a, T>) -> Result<Self, FromValueError> {
157 Ok(value)
158 }
159}
160
161impl<'a, T> TryFromValue<'a, T> for Function<'a, T> {
162 fn try_from_value(value: Value<'a, T>) -> Result<Self, FromValueError> {
163 match value {
164 Value::Function(function) => Ok(function),
165 _ => Err(FromValueError::invalid_type(ValueType::Function, &value)),
166 }
167 }
168}
169
170impl<'a, U, T> TryFromValue<'a, T> for Vec<U>
171where
172 U: TryFromValue<'a, T>,
173{
174 fn try_from_value(value: Value<'a, T>) -> Result<Self, FromValueError> {
175 match value {
176 Value::Tuple(values) => {
177 let tuple_len = values.len();
178 let mut collected = Vec::with_capacity(tuple_len);
179
180 for (index, element) in values.into_iter().enumerate() {
181 let converted = U::try_from_value(element).map_err(|err| {
182 err.add_location(FromValueErrorLocation::Array {
183 size: tuple_len,
184 index,
185 })
186 })?;
187 collected.push(converted);
188 }
189 Ok(collected)
190 }
191 _ => Err(FromValueError::invalid_type(ValueType::Array, &value)),
192 }
193 }
194}
195
196macro_rules! try_from_value_for_tuple {
197 ($size:expr => $($var:ident : $ty:ident),+) => {
198 impl<'a, Num, $($ty,)+> TryFromValue<'a, Num> for ($($ty,)+)
199 where
200 $($ty: TryFromValue<'a, Num>,)+
201 {
202 #[allow(clippy::shadow_unrelated)] fn try_from_value(value: Value<'a, Num>) -> Result<Self, FromValueError> {
204 const EXPECTED_TYPE: ValueType = ValueType::Tuple($size);
205
206 match value {
207 Value::Tuple(values) if values.len() == $size => {
208 let mut values_iter = values.into_iter().enumerate();
209 $(
210 let (index, $var) = values_iter.next().unwrap();
211 let $var = $ty::try_from_value($var).map_err(|err| {
212 err.add_location(FromValueErrorLocation::Tuple {
213 size: $size,
214 index,
215 })
216 })?;
217 )+
218 Ok(($($var,)+))
219 }
220 _ => Err(FromValueError::invalid_type(EXPECTED_TYPE, &value)),
221 }
222 }
223 }
224 };
225}
226
227try_from_value_for_tuple!(1 => x0: T);
228try_from_value_for_tuple!(2 => x0: T, x1: U);
229try_from_value_for_tuple!(3 => x0: T, x1: U, x2: V);
230try_from_value_for_tuple!(4 => x0: T, x1: U, x2: V, x3: W);
231try_from_value_for_tuple!(5 => x0: T, x1: U, x2: V, x3: W, x4: X);
232try_from_value_for_tuple!(6 => x0: T, x1: U, x2: V, x3: W, x4: X, x5: Y);
233try_from_value_for_tuple!(7 => x0: T, x1: U, x2: V, x3: W, x4: X, x5: Y, x6: Z);
234try_from_value_for_tuple!(8 => x0: T, x1: U, x2: V, x3: W, x4: X, x5: Y, x6: Z, x7: A);
235try_from_value_for_tuple!(9 => x0: T, x1: U, x2: V, x3: W, x4: X, x5: Y, x6: Z, x7: A, x8: B);
236try_from_value_for_tuple!(10 => x0: T, x1: U, x2: V, x3: W, x4: X, x5: Y, x6: Z, x7: A, x8: B, x9: C);
237
238#[derive(Debug)]
241#[non_exhaustive]
242pub enum ErrorOutput<'a> {
243 Spanned(Error<'a>),
245 Message(String),
247}
248
249impl<'a> ErrorOutput<'a> {
250 #[doc(hidden)] pub fn into_spanned<A>(self, context: &CallContext<'_, 'a, A>) -> Error<'a> {
252 match self {
253 Self::Spanned(err) => err,
254 Self::Message(message) => context.call_site_error(ErrorKind::native(message)),
255 }
256 }
257}
258
259pub trait IntoEvalResult<'a, T> {
272 fn into_eval_result(self) -> Result<Value<'a, T>, ErrorOutput<'a>>;
274}
275
276impl<'a, T, U> IntoEvalResult<'a, T> for Result<U, String>
277where
278 U: IntoEvalResult<'a, T>,
279{
280 fn into_eval_result(self) -> Result<Value<'a, T>, ErrorOutput<'a>> {
281 self.map_err(ErrorOutput::Message)
282 .and_then(U::into_eval_result)
283 }
284}
285
286impl<'a, T, U> IntoEvalResult<'a, T> for Result<U, Error<'a>>
287where
288 U: IntoEvalResult<'a, T>,
289{
290 fn into_eval_result(self) -> Result<Value<'a, T>, ErrorOutput<'a>> {
291 self.map_err(ErrorOutput::Spanned)
292 .and_then(U::into_eval_result)
293 }
294}
295
296impl<'a, T: Number> IntoEvalResult<'a, T> for T {
297 fn into_eval_result(self) -> Result<Value<'a, T>, ErrorOutput<'a>> {
298 Ok(Value::Prim(self))
299 }
300}
301
302impl<'a, T> IntoEvalResult<'a, T> for () {
303 fn into_eval_result(self) -> Result<Value<'a, T>, ErrorOutput<'a>> {
304 Ok(Value::void())
305 }
306}
307
308impl<'a, T> IntoEvalResult<'a, T> for bool {
309 fn into_eval_result(self) -> Result<Value<'a, T>, ErrorOutput<'a>> {
310 Ok(Value::Bool(self))
311 }
312}
313
314impl<'a, T> IntoEvalResult<'a, T> for cmp::Ordering {
315 fn into_eval_result(self) -> Result<Value<'a, T>, ErrorOutput<'a>> {
316 Ok(Value::opaque_ref(self))
317 }
318}
319
320impl<'a, T> IntoEvalResult<'a, T> for Value<'a, T> {
321 fn into_eval_result(self) -> Result<Value<'a, T>, ErrorOutput<'a>> {
322 Ok(self)
323 }
324}
325
326impl<'a, T> IntoEvalResult<'a, T> for Function<'a, T> {
327 fn into_eval_result(self) -> Result<Value<'a, T>, ErrorOutput<'a>> {
328 Ok(Value::Function(self))
329 }
330}
331
332impl<'a, U, T> IntoEvalResult<'a, T> for Vec<U>
333where
334 U: IntoEvalResult<'a, T>,
335{
336 fn into_eval_result(self) -> Result<Value<'a, T>, ErrorOutput<'a>> {
337 let values = self
338 .into_iter()
339 .map(U::into_eval_result)
340 .collect::<Result<Vec<_>, _>>()?;
341 Ok(Value::Tuple(values))
342 }
343}
344
345macro_rules! into_value_for_tuple {
346 ($($i:tt : $ty:ident),+) => {
347 impl<'a, Num, $($ty,)+> IntoEvalResult<'a, Num> for ($($ty,)+)
348 where
349 $($ty: IntoEvalResult<'a, Num>,)+
350 {
351 fn into_eval_result(self) -> Result<Value<'a, Num>, ErrorOutput<'a>> {
352 Ok(Value::Tuple(vec![$(self.$i.into_eval_result()?,)+]))
353 }
354 }
355 };
356}
357
358into_value_for_tuple!(0: T);
359into_value_for_tuple!(0: T, 1: U);
360into_value_for_tuple!(0: T, 1: U, 2: V);
361into_value_for_tuple!(0: T, 1: U, 2: V, 3: W);
362into_value_for_tuple!(0: T, 1: U, 2: V, 3: W, 4: X);
363into_value_for_tuple!(0: T, 1: U, 2: V, 3: W, 4: X, 5: Y);
364into_value_for_tuple!(0: T, 1: U, 2: V, 3: W, 4: X, 5: Y, 6: Z);
365into_value_for_tuple!(0: T, 1: U, 2: V, 3: W, 4: X, 5: Y, 6: Z, 7: A);
366into_value_for_tuple!(0: T, 1: U, 2: V, 3: W, 4: X, 5: Y, 6: Z, 7: A, 8: B);
367into_value_for_tuple!(0: T, 1: U, 2: V, 3: W, 4: X, 5: Y, 6: Z, 7: A, 8: B, 9: C);