1use crate::{
2 ast::{CellPath, PathMember},
3 engine::Closure,
4 NuGlob, Range, Record, ShellError, Span, Spanned, Type, Value,
5};
6use chrono::{DateTime, FixedOffset};
7use std::{
8 any,
9 cmp::Ordering,
10 collections::{HashMap, VecDeque},
11 fmt,
12 path::PathBuf,
13 str::FromStr,
14};
15
16pub trait FromValue: Sized {
115 fn from_value(v: Value) -> Result<Self, ShellError>;
121
122 fn expected_type() -> Type {
133 Type::Custom(
134 any::type_name::<Self>()
135 .split(':')
136 .last()
137 .expect("str::split returns an iterator with at least one element")
138 .to_string()
139 .into_boxed_str(),
140 )
141 }
142}
143
144impl<T, const N: usize> FromValue for [T; N]
147where
148 T: FromValue,
149{
150 fn from_value(v: Value) -> Result<Self, ShellError> {
151 let span = v.span();
152 let v_ty = v.get_type();
153 let vec = Vec::<T>::from_value(v)?;
154 vec.try_into()
155 .map_err(|err_vec: Vec<T>| ShellError::CantConvert {
156 to_type: Self::expected_type().to_string(),
157 from_type: v_ty.to_string(),
158 span,
159 help: Some(match err_vec.len().cmp(&N) {
160 Ordering::Less => format!(
161 "input list too short ({}), expected length of {N}, add missing values",
162 err_vec.len()
163 ),
164 Ordering::Equal => {
165 unreachable!("conversion would have worked if the length would be the same")
166 }
167 Ordering::Greater => format!(
168 "input list too long ({}), expected length of {N}, remove trailing values",
169 err_vec.len()
170 ),
171 }),
172 })
173 }
174
175 fn expected_type() -> Type {
176 Type::Custom(format!("list<{};{N}>", T::expected_type()).into_boxed_str())
177 }
178}
179
180impl FromValue for bool {
181 fn from_value(v: Value) -> Result<Self, ShellError> {
182 match v {
183 Value::Bool { val, .. } => Ok(val),
184 v => Err(ShellError::CantConvert {
185 to_type: Self::expected_type().to_string(),
186 from_type: v.get_type().to_string(),
187 span: v.span(),
188 help: None,
189 }),
190 }
191 }
192
193 fn expected_type() -> Type {
194 Type::Bool
195 }
196}
197
198impl FromValue for char {
199 fn from_value(v: Value) -> Result<Self, ShellError> {
200 let span = v.span();
201 let v_ty = v.get_type();
202 match v {
203 Value::String { ref val, .. } => match char::from_str(val) {
204 Ok(c) => Ok(c),
205 Err(_) => Err(ShellError::CantConvert {
206 to_type: Self::expected_type().to_string(),
207 from_type: v_ty.to_string(),
208 span,
209 help: Some("make the string only one char long".to_string()),
210 }),
211 },
212 _ => Err(ShellError::CantConvert {
213 to_type: Self::expected_type().to_string(),
214 from_type: v_ty.to_string(),
215 span,
216 help: None,
217 }),
218 }
219 }
220
221 fn expected_type() -> Type {
222 Type::String
223 }
224}
225
226impl FromValue for f32 {
227 fn from_value(v: Value) -> Result<Self, ShellError> {
228 f64::from_value(v).map(|float| float as f32)
229 }
230}
231
232impl FromValue for f64 {
233 fn from_value(v: Value) -> Result<Self, ShellError> {
234 match v {
235 Value::Float { val, .. } => Ok(val),
236 Value::Int { val, .. } => Ok(val as f64),
237 v => Err(ShellError::CantConvert {
238 to_type: Self::expected_type().to_string(),
239 from_type: v.get_type().to_string(),
240 span: v.span(),
241 help: None,
242 }),
243 }
244 }
245
246 fn expected_type() -> Type {
247 Type::Float
248 }
249}
250
251impl FromValue for i64 {
252 fn from_value(v: Value) -> Result<Self, ShellError> {
253 match v {
254 Value::Int { val, .. } => Ok(val),
255 Value::Duration { val, .. } => Ok(val),
256 v => Err(ShellError::CantConvert {
257 to_type: Self::expected_type().to_string(),
258 from_type: v.get_type().to_string(),
259 span: v.span(),
260 help: None,
261 }),
262 }
263 }
264
265 fn expected_type() -> Type {
266 Type::Int
267 }
268}
269
270macro_rules! impl_from_value_for_int {
271 ($type:ty) => {
272 impl FromValue for $type {
273 fn from_value(v: Value) -> Result<Self, ShellError> {
274 let span = v.span();
275 let int = i64::from_value(v)?;
276 const MIN: i64 = <$type>::MIN as i64;
277 const MAX: i64 = <$type>::MAX as i64;
278 #[allow(overlapping_range_endpoints)] #[allow(unreachable_patterns)] <$type>::try_from(int).map_err(|_| match int {
281 MIN..=MAX => unreachable!(
282 "int should be within the valid range for {}",
283 stringify!($type)
284 ),
285 i64::MIN..=MIN => int_too_small_error(int, <$type>::MIN, span),
286 MAX..=i64::MAX => int_too_large_error(int, <$type>::MAX, span),
287 })
288 }
289
290 fn expected_type() -> Type {
291 i64::expected_type()
292 }
293 }
294 };
295}
296
297impl_from_value_for_int!(i8);
298impl_from_value_for_int!(i16);
299impl_from_value_for_int!(i32);
300impl_from_value_for_int!(isize);
301
302macro_rules! impl_from_value_for_uint {
303 ($type:ty, $max:expr) => {
304 impl FromValue for $type {
305 fn from_value(v: Value) -> Result<Self, ShellError> {
306 let span = v.span();
307 const MAX: i64 = $max;
308 match v {
309 Value::Int { val, .. } | Value::Duration { val, .. } => {
310 match val {
311 i64::MIN..=-1 => Err(ShellError::NeedsPositiveValue { span }),
312 0..=MAX => Ok(val as $type),
313 #[allow(unreachable_patterns)] n => Err(ShellError::GenericError {
315 error: "Integer too large".to_string(),
316 msg: format!("{n} is larger than {MAX}"),
317 span: Some(span),
318 help: None,
319 inner: vec![],
320 }),
321 }
322 }
323 v => Err(ShellError::CantConvert {
324 to_type: Self::expected_type().to_string(),
325 from_type: v.get_type().to_string(),
326 span: v.span(),
327 help: None,
328 }),
329 }
330 }
331
332 fn expected_type() -> Type {
333 Type::Custom("non-negative int".to_string().into_boxed_str())
334 }
335 }
336 };
337}
338
339impl_from_value_for_uint!(u16, u16::MAX as i64);
346impl_from_value_for_uint!(u32, u32::MAX as i64);
347impl_from_value_for_uint!(u64, i64::MAX); #[cfg(target_pointer_width = "64")]
349impl_from_value_for_uint!(usize, i64::MAX);
350#[cfg(target_pointer_width = "32")]
351impl_from_value_for_uint!(usize, usize::MAX as i64);
352
353impl FromValue for () {
354 fn from_value(v: Value) -> Result<Self, ShellError> {
355 match v {
356 Value::Nothing { .. } => Ok(()),
357 v => Err(ShellError::CantConvert {
358 to_type: Self::expected_type().to_string(),
359 from_type: v.get_type().to_string(),
360 span: v.span(),
361 help: None,
362 }),
363 }
364 }
365
366 fn expected_type() -> Type {
367 Type::Nothing
368 }
369}
370
371macro_rules! tuple_from_value {
372 ($template:literal, $($t:ident:$n:tt),+) => {
373 impl<$($t),+> FromValue for ($($t,)+) where $($t: FromValue,)+ {
374 fn from_value(v: Value) -> Result<Self, ShellError> {
375 let span = v.span();
376 match v {
377 Value::List { vals, .. } => {
378 let mut deque = VecDeque::from(vals);
379
380 Ok(($(
381 {
382 let v = deque.pop_front().ok_or_else(|| ShellError::CantFindColumn {
383 col_name: $n.to_string(),
384 span: None,
385 src_span: span
386 })?;
387 $t::from_value(v)?
388 },
389 )*))
390 },
391 v => Err(ShellError::CantConvert {
392 to_type: Self::expected_type().to_string(),
393 from_type: v.get_type().to_string(),
394 span: v.span(),
395 help: None,
396 }),
397 }
398 }
399
400 fn expected_type() -> Type {
401 Type::Custom(
402 format!(
403 $template,
404 $($t::expected_type()),*
405 )
406 .into_boxed_str(),
407 )
408 }
409 }
410 };
411}
412
413tuple_from_value!("[{}]", T0:0);
415tuple_from_value!("[{}, {}]", T0:0, T1:1);
416tuple_from_value!("[{}, {}, {}]", T0:0, T1:1, T2:2);
417tuple_from_value!("[{}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3);
418tuple_from_value!("[{}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4);
419tuple_from_value!("[{}, {}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4, T5:5);
420tuple_from_value!("[{}, {}, {}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6);
421tuple_from_value!("[{}, {}, {}, {}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7);
422tuple_from_value!("[{}, {}, {}, {}, {}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8);
423tuple_from_value!("[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9);
424tuple_from_value!("[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10);
425tuple_from_value!("[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10, T11:11);
426
427impl FromValue for PathBuf {
430 fn from_value(v: Value) -> Result<Self, ShellError> {
431 match v {
432 Value::String { val, .. } => Ok(val.into()),
433 v => Err(ShellError::CantConvert {
434 to_type: Self::expected_type().to_string(),
435 from_type: v.get_type().to_string(),
436 span: v.span(),
437 help: None,
438 }),
439 }
440 }
441
442 fn expected_type() -> Type {
443 Type::String
444 }
445}
446
447impl FromValue for String {
448 fn from_value(v: Value) -> Result<Self, ShellError> {
449 match v {
451 Value::CellPath { val, .. } => Ok(val.to_string()),
452 Value::String { val, .. } => Ok(val),
453 v => Err(ShellError::CantConvert {
454 to_type: Self::expected_type().to_string(),
455 from_type: v.get_type().to_string(),
456 span: v.span(),
457 help: None,
458 }),
459 }
460 }
461
462 fn expected_type() -> Type {
463 Type::String
464 }
465}
466
467impl FromValue for Vec<u8> {
470 fn from_value(v: Value) -> Result<Self, ShellError> {
471 match v {
472 Value::Binary { val, .. } => Ok(val),
473 Value::String { val, .. } => Ok(val.into_bytes()),
474 Value::List { vals, .. } => {
475 const U8MIN: i64 = u8::MIN as i64;
476 const U8MAX: i64 = u8::MAX as i64;
477 let mut this = Vec::with_capacity(vals.len());
478 for val in vals {
479 let span = val.span();
480 let int = i64::from_value(val)?;
481 #[allow(overlapping_range_endpoints)]
483 #[allow(clippy::match_overlapping_arm)]
484 match int {
485 U8MIN..=U8MAX => this.push(int as u8),
486 i64::MIN..=U8MIN => return Err(int_too_small_error(int, U8MIN, span)),
487 U8MAX..=i64::MAX => return Err(int_too_large_error(int, U8MAX, span)),
488 };
489 }
490 Ok(this)
491 }
492 v => Err(ShellError::CantConvert {
493 to_type: Self::expected_type().to_string(),
494 from_type: v.get_type().to_string(),
495 span: v.span(),
496 help: None,
497 }),
498 }
499 }
500
501 fn expected_type() -> Type {
502 Type::Binary
503 }
504}
505
506impl<T> FromValue for Option<T>
509where
510 T: FromValue,
511{
512 fn from_value(v: Value) -> Result<Self, ShellError> {
513 match v {
514 Value::Nothing { .. } => Ok(None),
515 v => T::from_value(v).map(Option::Some),
516 }
517 }
518
519 fn expected_type() -> Type {
520 T::expected_type()
521 }
522}
523
524impl<V> FromValue for HashMap<String, V>
525where
526 V: FromValue,
527{
528 fn from_value(v: Value) -> Result<Self, ShellError> {
529 let record = v.into_record()?;
530 let items: Result<Vec<(String, V)>, ShellError> = record
531 .into_iter()
532 .map(|(k, v)| Ok((k, V::from_value(v)?)))
533 .collect();
534 Ok(HashMap::from_iter(items?))
535 }
536
537 fn expected_type() -> Type {
538 Type::Record(vec![].into_boxed_slice())
539 }
540}
541
542impl<T> FromValue for Vec<T>
543where
544 T: FromValue,
545{
546 fn from_value(v: Value) -> Result<Self, ShellError> {
547 match v {
548 Value::List { vals, .. } => vals
549 .into_iter()
550 .map(|v| T::from_value(v))
551 .collect::<Result<Vec<T>, ShellError>>(),
552 v => Err(ShellError::CantConvert {
553 to_type: Self::expected_type().to_string(),
554 from_type: v.get_type().to_string(),
555 span: v.span(),
556 help: None,
557 }),
558 }
559 }
560
561 fn expected_type() -> Type {
562 Type::List(Box::new(T::expected_type()))
563 }
564}
565
566impl FromValue for Value {
569 fn from_value(v: Value) -> Result<Self, ShellError> {
570 Ok(v)
571 }
572
573 fn expected_type() -> Type {
574 Type::Any
575 }
576}
577
578impl FromValue for CellPath {
579 fn from_value(v: Value) -> Result<Self, ShellError> {
580 let span = v.span();
581 match v {
582 Value::CellPath { val, .. } => Ok(val),
583 Value::String { val, .. } => Ok(CellPath {
584 members: vec![PathMember::String {
585 val,
586 span,
587 optional: false,
588 }],
589 }),
590 Value::Int { val, .. } => {
591 if val.is_negative() {
592 Err(ShellError::NeedsPositiveValue { span })
593 } else {
594 Ok(CellPath {
595 members: vec![PathMember::Int {
596 val: val as usize,
597 span,
598 optional: false,
599 }],
600 })
601 }
602 }
603 x => Err(ShellError::CantConvert {
604 to_type: Self::expected_type().to_string(),
605 from_type: x.get_type().to_string(),
606 span,
607 help: None,
608 }),
609 }
610 }
611
612 fn expected_type() -> Type {
613 Type::CellPath
614 }
615}
616
617impl FromValue for Closure {
618 fn from_value(v: Value) -> Result<Self, ShellError> {
619 match v {
620 Value::Closure { val, .. } => Ok(*val),
621 v => Err(ShellError::CantConvert {
622 to_type: Self::expected_type().to_string(),
623 from_type: v.get_type().to_string(),
624 span: v.span(),
625 help: None,
626 }),
627 }
628 }
629}
630
631impl FromValue for DateTime<FixedOffset> {
632 fn from_value(v: Value) -> Result<Self, ShellError> {
633 match v {
634 Value::Date { val, .. } => Ok(val),
635 v => Err(ShellError::CantConvert {
636 to_type: Self::expected_type().to_string(),
637 from_type: v.get_type().to_string(),
638 span: v.span(),
639 help: None,
640 }),
641 }
642 }
643
644 fn expected_type() -> Type {
645 Type::Date
646 }
647}
648
649impl FromValue for NuGlob {
650 fn from_value(v: Value) -> Result<Self, ShellError> {
651 match v {
653 Value::CellPath { val, .. } => Ok(NuGlob::Expand(val.to_string())),
654 Value::String { val, .. } => Ok(NuGlob::DoNotExpand(val)),
655 Value::Glob {
656 val,
657 no_expand: quoted,
658 ..
659 } => {
660 if quoted {
661 Ok(NuGlob::DoNotExpand(val))
662 } else {
663 Ok(NuGlob::Expand(val))
664 }
665 }
666 v => Err(ShellError::CantConvert {
667 to_type: Self::expected_type().to_string(),
668 from_type: v.get_type().to_string(),
669 span: v.span(),
670 help: None,
671 }),
672 }
673 }
674
675 fn expected_type() -> Type {
676 Type::String
677 }
678}
679
680impl FromValue for Range {
681 fn from_value(v: Value) -> Result<Self, ShellError> {
682 match v {
683 Value::Range { val, .. } => Ok(*val),
684 v => Err(ShellError::CantConvert {
685 to_type: Self::expected_type().to_string(),
686 from_type: v.get_type().to_string(),
687 span: v.span(),
688 help: None,
689 }),
690 }
691 }
692
693 fn expected_type() -> Type {
694 Type::Range
695 }
696}
697
698impl FromValue for Record {
699 fn from_value(v: Value) -> Result<Self, ShellError> {
700 match v {
701 Value::Record { val, .. } => Ok(val.into_owned()),
702 v => Err(ShellError::CantConvert {
703 to_type: Self::expected_type().to_string(),
704 from_type: v.get_type().to_string(),
705 span: v.span(),
706 help: None,
707 }),
708 }
709 }
710}
711
712impl<T> FromValue for Spanned<T>
715where
716 T: FromValue,
717{
718 fn from_value(v: Value) -> Result<Self, ShellError> {
719 let span = v.span();
720 Ok(Spanned {
721 item: T::from_value(v)?,
722 span,
723 })
724 }
725
726 fn expected_type() -> Type {
727 T::expected_type()
728 }
729}
730
731impl FromValue for bytes::Bytes {
734 fn from_value(v: Value) -> Result<Self, ShellError> {
735 match v {
736 Value::Binary { val, .. } => Ok(val.into()),
737 v => Err(ShellError::CantConvert {
738 to_type: Self::expected_type().to_string(),
739 from_type: v.get_type().to_string(),
740 span: v.span(),
741 help: None,
742 }),
743 }
744 }
745
746 fn expected_type() -> Type {
747 Type::Binary
748 }
749}
750
751fn int_too_small_error(int: impl fmt::Display, min: impl fmt::Display, span: Span) -> ShellError {
753 ShellError::GenericError {
754 error: "Integer too small".to_string(),
755 msg: format!("{int} is smaller than {min}"),
756 span: Some(span),
757 help: None,
758 inner: vec![],
759 }
760}
761
762fn int_too_large_error(int: impl fmt::Display, max: impl fmt::Display, span: Span) -> ShellError {
763 ShellError::GenericError {
764 error: "Integer too large".to_string(),
765 msg: format!("{int} is larger than {max}"),
766 span: Some(span),
767 help: None,
768 inner: vec![],
769 }
770}
771
772#[cfg(test)]
773mod tests {
774 use crate::{engine::Closure, FromValue, IntoValue, Record, Span, Type, Value};
775 use std::ops::Deref;
776
777 #[test]
778 fn expected_type_default_impl() {
779 assert_eq!(
780 Record::expected_type(),
781 Type::Custom("Record".to_string().into_boxed_str())
782 );
783
784 assert_eq!(
785 Closure::expected_type(),
786 Type::Custom("Closure".to_string().into_boxed_str())
787 );
788 }
789
790 #[test]
791 fn from_value_vec_u8() {
792 let vec: Vec<u8> = vec![1, 2, 3];
793 let span = Span::test_data();
794 let string = "Hello Vec<u8>!".to_string();
795
796 assert_eq!(
797 Vec::<u8>::from_value(vec.clone().into_value(span)).unwrap(),
798 vec.clone(),
799 "Vec<u8> roundtrip"
800 );
801
802 assert_eq!(
803 Vec::<u8>::from_value(Value::test_string(string.clone()))
804 .unwrap()
805 .deref(),
806 string.as_bytes(),
807 "Vec<u8> from String"
808 );
809
810 assert_eq!(
811 Vec::<u8>::from_value(Value::test_binary(vec.clone())).unwrap(),
812 vec,
813 "Vec<u8> from Binary"
814 );
815
816 assert!(Vec::<u8>::from_value(vec![u8::MIN as i32 - 1].into_value(span)).is_err());
817 assert!(Vec::<u8>::from_value(vec![u8::MAX as i32 + 1].into_value(span)).is_err());
818 }
819}