1use core::{cmp, fmt};
4
5use crate::{
6 alloc::{vec, String, Vec},
7 CallContext, Error, ErrorKind, Function, Number, Object, Tuple, 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, Eq)]
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 {actual} to {expected}")
96 }
97 }
98 }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq)]
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<T>: Sized {
133 fn try_from_value(value: Value<T>) -> Result<Self, FromValueError>;
135}
136
137impl<T: Number> TryFromValue<T> for T {
138 fn try_from_value(value: Value<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<T> TryFromValue<T> for bool {
147 fn try_from_value(value: Value<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<T> TryFromValue<T> for Value<T> {
156 fn try_from_value(value: Value<T>) -> Result<Self, FromValueError> {
157 Ok(value)
158 }
159}
160
161impl<T> TryFromValue<T> for Function<T> {
162 fn try_from_value(value: Value<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<T> TryFromValue<T> for Tuple<T> {
171 fn try_from_value(value: Value<T>) -> Result<Self, FromValueError> {
172 match value {
173 Value::Tuple(tuple) => Ok(tuple),
174 _ => Err(FromValueError::invalid_type(ValueType::Array, &value)),
175 }
176 }
177}
178
179impl<T> TryFromValue<T> for Object<T> {
180 fn try_from_value(value: Value<T>) -> Result<Self, FromValueError> {
181 match value {
182 Value::Object(object) => Ok(object),
183 _ => Err(FromValueError::invalid_type(ValueType::Object, &value)),
184 }
185 }
186}
187
188impl<U, T> TryFromValue<T> for Vec<U>
189where
190 U: TryFromValue<T>,
191{
192 fn try_from_value(value: Value<T>) -> Result<Self, FromValueError> {
193 match value {
194 Value::Tuple(values) => {
195 let tuple_len = values.len();
196 let mut collected = Vec::with_capacity(tuple_len);
197
198 for (index, element) in values.into_iter().enumerate() {
199 let converted = U::try_from_value(element).map_err(|err| {
200 err.add_location(FromValueErrorLocation::Array {
201 size: tuple_len,
202 index,
203 })
204 })?;
205 collected.push(converted);
206 }
207 Ok(collected)
208 }
209 _ => Err(FromValueError::invalid_type(ValueType::Array, &value)),
210 }
211 }
212}
213
214macro_rules! try_from_value_for_tuple {
215 ($size:expr => $($var:ident : $ty:ident),+) => {
216 impl<Num, $($ty,)+> TryFromValue<Num> for ($($ty,)+)
217 where
218 $($ty: TryFromValue<Num>,)+
219 {
220 #[allow(clippy::shadow_unrelated)] fn try_from_value(value: Value<Num>) -> Result<Self, FromValueError> {
222 const EXPECTED_TYPE: ValueType = ValueType::Tuple($size);
223
224 match value {
225 Value::Tuple(values) if values.len() == $size => {
226 let mut values_iter = values.into_iter().enumerate();
227 $(
228 let (index, $var) = values_iter.next().unwrap();
229 let $var = $ty::try_from_value($var).map_err(|err| {
230 err.add_location(FromValueErrorLocation::Tuple {
231 size: $size,
232 index,
233 })
234 })?;
235 )+
236 Ok(($($var,)+))
237 }
238 _ => Err(FromValueError::invalid_type(EXPECTED_TYPE, &value)),
239 }
240 }
241 }
242 };
243}
244
245try_from_value_for_tuple!(1 => x0: T);
246try_from_value_for_tuple!(2 => x0: T, x1: U);
247try_from_value_for_tuple!(3 => x0: T, x1: U, x2: V);
248try_from_value_for_tuple!(4 => x0: T, x1: U, x2: V, x3: W);
249try_from_value_for_tuple!(5 => x0: T, x1: U, x2: V, x3: W, x4: X);
250try_from_value_for_tuple!(6 => x0: T, x1: U, x2: V, x3: W, x4: X, x5: Y);
251try_from_value_for_tuple!(7 => x0: T, x1: U, x2: V, x3: W, x4: X, x5: Y, x6: Z);
252try_from_value_for_tuple!(8 => x0: T, x1: U, x2: V, x3: W, x4: X, x5: Y, x6: Z, x7: A);
253try_from_value_for_tuple!(9 => x0: T, x1: U, x2: V, x3: W, x4: X, x5: Y, x6: Z, x7: A, x8: B);
254try_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);
255
256#[derive(Debug)]
259#[non_exhaustive]
260pub enum ErrorOutput {
261 Spanned(Error),
263 Message(String),
265}
266
267impl ErrorOutput {
268 #[doc(hidden)] pub fn into_spanned<A>(self, context: &CallContext<'_, A>) -> Error {
270 match self {
271 Self::Spanned(err) => err,
272 Self::Message(message) => context.call_site_error(ErrorKind::native(message)),
273 }
274 }
275}
276
277pub trait IntoEvalResult<T> {
290 fn into_eval_result(self) -> Result<Value<T>, ErrorOutput>;
292}
293
294impl<T, U> IntoEvalResult<T> for Result<U, String>
295where
296 U: IntoEvalResult<T>,
297{
298 fn into_eval_result(self) -> Result<Value<T>, ErrorOutput> {
299 self.map_err(ErrorOutput::Message)
300 .and_then(U::into_eval_result)
301 }
302}
303
304impl<T, U> IntoEvalResult<T> for Result<U, Error>
305where
306 U: IntoEvalResult<T>,
307{
308 fn into_eval_result(self) -> Result<Value<T>, ErrorOutput> {
309 self.map_err(ErrorOutput::Spanned)
310 .and_then(U::into_eval_result)
311 }
312}
313
314impl<T: Number> IntoEvalResult<T> for T {
315 fn into_eval_result(self) -> Result<Value<T>, ErrorOutput> {
316 Ok(Value::Prim(self))
317 }
318}
319
320impl<T> IntoEvalResult<T> for () {
321 fn into_eval_result(self) -> Result<Value<T>, ErrorOutput> {
322 Ok(Value::void())
323 }
324}
325
326impl<T> IntoEvalResult<T> for bool {
327 fn into_eval_result(self) -> Result<Value<T>, ErrorOutput> {
328 Ok(Value::Bool(self))
329 }
330}
331
332impl<T> IntoEvalResult<T> for cmp::Ordering {
333 fn into_eval_result(self) -> Result<Value<T>, ErrorOutput> {
334 Ok(Value::opaque_ref(self))
335 }
336}
337
338impl<T> IntoEvalResult<T> for Value<T> {
339 fn into_eval_result(self) -> Result<Value<T>, ErrorOutput> {
340 Ok(self)
341 }
342}
343
344impl<T> IntoEvalResult<T> for Function<T> {
345 fn into_eval_result(self) -> Result<Value<T>, ErrorOutput> {
346 Ok(Value::Function(self))
347 }
348}
349
350impl<T> IntoEvalResult<T> for Tuple<T> {
351 fn into_eval_result(self) -> Result<Value<T>, ErrorOutput> {
352 Ok(Value::Tuple(self))
353 }
354}
355
356impl<T> IntoEvalResult<T> for Object<T> {
357 fn into_eval_result(self) -> Result<Value<T>, ErrorOutput> {
358 Ok(Value::Object(self))
359 }
360}
361
362impl<U, T> IntoEvalResult<T> for Vec<U>
363where
364 U: IntoEvalResult<T>,
365{
366 fn into_eval_result(self) -> Result<Value<T>, ErrorOutput> {
367 let values = self
368 .into_iter()
369 .map(U::into_eval_result)
370 .collect::<Result<Tuple<_>, _>>()?;
371 Ok(Value::Tuple(values))
372 }
373}
374
375macro_rules! into_value_for_tuple {
376 ($($i:tt : $ty:ident),+) => {
377 impl<Num, $($ty,)+> IntoEvalResult<Num> for ($($ty,)+)
378 where
379 $($ty: IntoEvalResult<Num>,)+
380 {
381 fn into_eval_result(self) -> Result<Value<Num>, ErrorOutput> {
382 Ok(Value::from(vec![$(self.$i.into_eval_result()?,)+]))
383 }
384 }
385 };
386}
387
388into_value_for_tuple!(0: T);
389into_value_for_tuple!(0: T, 1: U);
390into_value_for_tuple!(0: T, 1: U, 2: V);
391into_value_for_tuple!(0: T, 1: U, 2: V, 3: W);
392into_value_for_tuple!(0: T, 1: U, 2: V, 3: W, 4: X);
393into_value_for_tuple!(0: T, 1: U, 2: V, 3: W, 4: X, 5: Y);
394into_value_for_tuple!(0: T, 1: U, 2: V, 3: W, 4: X, 5: Y, 6: Z);
395into_value_for_tuple!(0: T, 1: U, 2: V, 3: W, 4: X, 5: Y, 6: Z, 7: A);
396into_value_for_tuple!(0: T, 1: U, 2: V, 3: W, 4: X, 5: Y, 6: Z, 7: A, 8: B);
397into_value_for_tuple!(0: T, 1: U, 2: V, 3: W, 4: X, 5: Y, 6: Z, 7: A, 8: B, 9: C);