1use crate::{
2 NuGlob, Range, Record, ShellError, Span, Spanned, Type, Value,
3 ast::{CellPath, PathMember},
4 casing::Casing,
5 engine::Closure,
6};
7use chrono::{DateTime, FixedOffset};
8use std::{
9 any,
10 borrow::Cow,
11 cmp::Ordering,
12 collections::{HashMap, VecDeque},
13 fmt,
14 num::{
15 NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroIsize, NonZeroU16, NonZeroU32,
16 NonZeroU64, NonZeroUsize,
17 },
18 path::PathBuf,
19 str::FromStr,
20};
21
22pub trait FromValue: Sized {
123 fn from_value(v: Value) -> Result<Self, ShellError>;
129
130 fn expected_type() -> Type {
141 Type::Custom(
142 any::type_name::<Self>()
143 .split(':')
144 .next_back()
145 .expect("str::split returns an iterator with at least one element")
146 .to_string()
147 .into_boxed_str(),
148 )
149 }
150}
151
152impl<T, const N: usize> FromValue for [T; N]
155where
156 T: FromValue,
157{
158 fn from_value(v: Value) -> Result<Self, ShellError> {
159 let span = v.span();
160 let v_ty = v.get_type();
161 let vec = Vec::<T>::from_value(v)?;
162 vec.try_into()
163 .map_err(|err_vec: Vec<T>| ShellError::CantConvert {
164 to_type: Self::expected_type().to_string(),
165 from_type: v_ty.to_string(),
166 span,
167 help: Some(match err_vec.len().cmp(&N) {
168 Ordering::Less => format!(
169 "input list too short ({}), expected length of {N}, add missing values",
170 err_vec.len()
171 ),
172 Ordering::Equal => {
173 unreachable!("conversion would have worked if the length would be the same")
174 }
175 Ordering::Greater => format!(
176 "input list too long ({}), expected length of {N}, remove trailing values",
177 err_vec.len()
178 ),
179 }),
180 })
181 }
182
183 fn expected_type() -> Type {
184 Type::Custom(format!("list<{};{N}>", T::expected_type()).into_boxed_str())
185 }
186}
187
188impl FromValue for bool {
189 fn from_value(v: Value) -> Result<Self, ShellError> {
190 match v {
191 Value::Bool { val, .. } => Ok(val),
192 v => Err(ShellError::CantConvert {
193 to_type: Self::expected_type().to_string(),
194 from_type: v.get_type().to_string(),
195 span: v.span(),
196 help: None,
197 }),
198 }
199 }
200
201 fn expected_type() -> Type {
202 Type::Bool
203 }
204}
205
206impl FromValue for char {
207 fn from_value(v: Value) -> Result<Self, ShellError> {
208 let span = v.span();
209 let v_ty = v.get_type();
210 match v {
211 Value::String { ref val, .. } => match char::from_str(val) {
212 Ok(c) => Ok(c),
213 Err(_) => Err(ShellError::CantConvert {
214 to_type: Self::expected_type().to_string(),
215 from_type: v_ty.to_string(),
216 span,
217 help: Some("make the string only one char long".to_string()),
218 }),
219 },
220 _ => Err(ShellError::CantConvert {
221 to_type: Self::expected_type().to_string(),
222 from_type: v_ty.to_string(),
223 span,
224 help: None,
225 }),
226 }
227 }
228
229 fn expected_type() -> Type {
230 Type::String
231 }
232}
233
234impl FromValue for f32 {
235 fn from_value(v: Value) -> Result<Self, ShellError> {
236 f64::from_value(v).map(|float| float as f32)
237 }
238}
239
240impl FromValue for f64 {
241 fn from_value(v: Value) -> Result<Self, ShellError> {
242 match v {
243 Value::Float { val, .. } => Ok(val),
244 Value::Int { val, .. } => Ok(val as f64),
245 v => Err(ShellError::CantConvert {
246 to_type: Self::expected_type().to_string(),
247 from_type: v.get_type().to_string(),
248 span: v.span(),
249 help: None,
250 }),
251 }
252 }
253
254 fn expected_type() -> Type {
255 Type::Float
256 }
257}
258
259impl FromValue for i64 {
260 fn from_value(v: Value) -> Result<Self, ShellError> {
261 match v {
262 Value::Int { val, .. } => Ok(val),
263 Value::Duration { val, .. } => Ok(val),
264 v => Err(ShellError::CantConvert {
265 to_type: Self::expected_type().to_string(),
266 from_type: v.get_type().to_string(),
267 span: v.span(),
268 help: None,
269 }),
270 }
271 }
272
273 fn expected_type() -> Type {
274 Type::Int
275 }
276}
277
278impl FromValue for std::time::Duration {
280 fn from_value(v: Value) -> Result<Self, ShellError> {
281 match v {
282 Value::Duration { val, .. } => {
283 let nanos = u64::try_from(val)
284 .map_err(|_| ShellError::NeedsPositiveValue { span: v.span() })?;
285 Ok(Self::from_nanos(nanos))
286 }
287 v => Err(ShellError::CantConvert {
288 to_type: Self::expected_type().to_string(),
289 from_type: v.get_type().to_string(),
290 span: v.span(),
291 help: None,
292 }),
293 }
294 }
295
296 fn expected_type() -> Type {
297 Type::Duration
298 }
299}
300
301macro_rules! impl_from_value_for_nonzero {
307 ($nonzero:ty, $base:ty) => {
308 impl FromValue for $nonzero {
309 fn from_value(v: Value) -> Result<Self, ShellError> {
310 let span = v.span();
311 let val = <$base>::from_value(v)?;
312 <$nonzero>::new(val).ok_or_else(|| ShellError::IncorrectValue {
313 msg: "use a value other than 0".into(),
314 val_span: span,
315 call_span: span,
316 })
317 }
318
319 fn expected_type() -> Type {
320 Type::Int
321 }
322 }
323 };
324}
325
326impl_from_value_for_nonzero!(NonZeroU16, u16);
327impl_from_value_for_nonzero!(NonZeroU32, u32);
328impl_from_value_for_nonzero!(NonZeroU64, u64);
329impl_from_value_for_nonzero!(NonZeroUsize, usize);
330
331impl_from_value_for_nonzero!(NonZeroI8, i8);
332impl_from_value_for_nonzero!(NonZeroI16, i16);
333impl_from_value_for_nonzero!(NonZeroI32, i32);
334impl_from_value_for_nonzero!(NonZeroI64, i64);
335impl_from_value_for_nonzero!(NonZeroIsize, isize);
336
337macro_rules! impl_from_value_for_int {
338 ($type:ty) => {
339 impl FromValue for $type {
340 fn from_value(v: Value) -> Result<Self, ShellError> {
341 let span = v.span();
342 let int = i64::from_value(v)?;
343 const MIN: i64 = <$type>::MIN as i64;
344 const MAX: i64 = <$type>::MAX as i64;
345 #[allow(overlapping_range_endpoints)] #[allow(unreachable_patterns)] <$type>::try_from(int).map_err(|_| match int {
348 MIN..=MAX => unreachable!(
349 "int should be within the valid range for {}",
350 stringify!($type)
351 ),
352 i64::MIN..=MIN => int_too_small_error(int, <$type>::MIN, span),
353 MAX..=i64::MAX => int_too_large_error(int, <$type>::MAX, span),
354 })
355 }
356
357 fn expected_type() -> Type {
358 i64::expected_type()
359 }
360 }
361 };
362}
363
364impl_from_value_for_int!(i8);
365impl_from_value_for_int!(i16);
366impl_from_value_for_int!(i32);
367impl_from_value_for_int!(isize);
368
369macro_rules! impl_from_value_for_uint {
370 ($type:ty, $max:expr) => {
371 impl FromValue for $type {
372 fn from_value(v: Value) -> Result<Self, ShellError> {
373 let span = v.span();
374 const MAX: i64 = $max;
375 match v {
376 Value::Int { val, .. } | Value::Duration { val, .. } => {
377 match val {
378 i64::MIN..=-1 => Err(ShellError::NeedsPositiveValue { span }),
379 0..=MAX => Ok(val as $type),
380 #[allow(unreachable_patterns)] n => Err(ShellError::GenericError {
382 error: "Integer too large".to_string(),
383 msg: format!("{n} is larger than {MAX}"),
384 span: Some(span),
385 help: None,
386 inner: vec![],
387 }),
388 }
389 }
390 v => Err(ShellError::CantConvert {
391 to_type: Self::expected_type().to_string(),
392 from_type: v.get_type().to_string(),
393 span: v.span(),
394 help: None,
395 }),
396 }
397 }
398
399 fn expected_type() -> Type {
400 Type::Custom("non-negative int".to_string().into_boxed_str())
401 }
402 }
403 };
404}
405
406impl_from_value_for_uint!(u16, u16::MAX as i64);
413impl_from_value_for_uint!(u32, u32::MAX as i64);
414impl_from_value_for_uint!(u64, i64::MAX); #[cfg(target_pointer_width = "64")]
416impl_from_value_for_uint!(usize, i64::MAX);
417#[cfg(target_pointer_width = "32")]
418impl_from_value_for_uint!(usize, usize::MAX as i64);
419
420impl FromValue for () {
421 fn from_value(v: Value) -> Result<Self, ShellError> {
422 match v {
423 Value::Nothing { .. } => Ok(()),
424 v => Err(ShellError::CantConvert {
425 to_type: Self::expected_type().to_string(),
426 from_type: v.get_type().to_string(),
427 span: v.span(),
428 help: None,
429 }),
430 }
431 }
432
433 fn expected_type() -> Type {
434 Type::Nothing
435 }
436}
437
438macro_rules! tuple_from_value {
439 ($template:literal, $($t:ident:$n:tt),+) => {
440 impl<$($t),+> FromValue for ($($t,)+) where $($t: FromValue,)+ {
441 fn from_value(v: Value) -> Result<Self, ShellError> {
442 let span = v.span();
443 match v {
444 Value::List { vals, .. } => {
445 let mut deque = VecDeque::from(vals);
446
447 Ok(($(
448 {
449 let v = deque.pop_front().ok_or_else(|| ShellError::CantFindColumn {
450 col_name: $n.to_string(),
451 span: None,
452 src_span: span
453 })?;
454 $t::from_value(v)?
455 },
456 )*))
457 },
458 v => Err(ShellError::CantConvert {
459 to_type: Self::expected_type().to_string(),
460 from_type: v.get_type().to_string(),
461 span: v.span(),
462 help: None,
463 }),
464 }
465 }
466
467 fn expected_type() -> Type {
468 Type::Custom(
469 format!(
470 $template,
471 $($t::expected_type()),*
472 )
473 .into_boxed_str(),
474 )
475 }
476 }
477 };
478}
479
480tuple_from_value!("[{}]", T0:0);
482tuple_from_value!("[{}, {}]", T0:0, T1:1);
483tuple_from_value!("[{}, {}, {}]", T0:0, T1:1, T2:2);
484tuple_from_value!("[{}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3);
485tuple_from_value!("[{}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4);
486tuple_from_value!("[{}, {}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4, T5:5);
487tuple_from_value!("[{}, {}, {}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6);
488tuple_from_value!("[{}, {}, {}, {}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7);
489tuple_from_value!("[{}, {}, {}, {}, {}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8);
490tuple_from_value!("[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9);
491tuple_from_value!("[{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}]", T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10);
492tuple_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);
493
494impl FromValue for PathBuf {
497 fn from_value(v: Value) -> Result<Self, ShellError> {
498 match v {
499 Value::String { val, .. } => Ok(val.into()),
500 v => Err(ShellError::CantConvert {
501 to_type: Self::expected_type().to_string(),
502 from_type: v.get_type().to_string(),
503 span: v.span(),
504 help: None,
505 }),
506 }
507 }
508
509 fn expected_type() -> Type {
510 Type::String
511 }
512}
513
514impl FromValue for String {
515 fn from_value(v: Value) -> Result<Self, ShellError> {
516 match v {
518 Value::CellPath { val, .. } => Ok(val.to_string()),
519 Value::String { val, .. } => Ok(val),
520 v => Err(ShellError::CantConvert {
521 to_type: Self::expected_type().to_string(),
522 from_type: v.get_type().to_string(),
523 span: v.span(),
524 help: None,
525 }),
526 }
527 }
528
529 fn expected_type() -> Type {
530 Type::String
531 }
532}
533
534impl FromValue for Vec<u8> {
537 fn from_value(v: Value) -> Result<Self, ShellError> {
538 match v {
539 Value::Binary { val, .. } => Ok(val),
540 Value::String { val, .. } => Ok(val.into_bytes()),
541 Value::List { vals, .. } => {
542 const U8MIN: i64 = u8::MIN as i64;
543 const U8MAX: i64 = u8::MAX as i64;
544 let mut this = Vec::with_capacity(vals.len());
545 for val in vals {
546 let span = val.span();
547 let int = i64::from_value(val)?;
548 #[allow(overlapping_range_endpoints)]
550 #[allow(clippy::match_overlapping_arm)]
551 match int {
552 U8MIN..=U8MAX => this.push(int as u8),
553 i64::MIN..=U8MIN => return Err(int_too_small_error(int, U8MIN, span)),
554 U8MAX..=i64::MAX => return Err(int_too_large_error(int, U8MAX, span)),
555 };
556 }
557 Ok(this)
558 }
559 v => Err(ShellError::CantConvert {
560 to_type: Self::expected_type().to_string(),
561 from_type: v.get_type().to_string(),
562 span: v.span(),
563 help: None,
564 }),
565 }
566 }
567
568 fn expected_type() -> Type {
569 Type::Binary
570 }
571}
572
573impl<T> FromValue for Option<T>
576where
577 T: FromValue,
578{
579 fn from_value(v: Value) -> Result<Self, ShellError> {
580 match v {
581 Value::Nothing { .. } => Ok(None),
582 v => T::from_value(v).map(Option::Some),
583 }
584 }
585
586 fn expected_type() -> Type {
587 T::expected_type()
588 }
589}
590
591impl<A, B> FromValue for Result<A, B>
592where
593 A: FromValue,
594 B: FromValue,
595{
596 fn from_value(v: Value) -> std::result::Result<Self, ShellError> {
597 match (A::from_value(v.clone()), B::from_value(v.clone())) {
598 (Ok(a), _) => Ok(Ok(a)),
599 (_, Ok(b)) => Ok(Err(b)),
600 (Err(ea), Err(_)) => Err(ea),
601 }
602 }
603
604 fn expected_type() -> Type {
605 Type::OneOf(vec![A::expected_type(), B::expected_type()].into())
606 }
607}
608
609impl<B> FromValue for Cow<'_, B>
615where
616 B: ?Sized + ToOwned,
617 B::Owned: FromValue,
618{
619 fn from_value(v: Value) -> Result<Self, ShellError> {
620 <B::Owned as FromValue>::from_value(v).map(Cow::Owned)
621 }
622
623 fn expected_type() -> Type {
624 <B::Owned as FromValue>::expected_type()
625 }
626}
627
628impl<V> FromValue for HashMap<String, V>
629where
630 V: FromValue,
631{
632 fn from_value(v: Value) -> Result<Self, ShellError> {
633 let record = v.into_record()?;
634 let items: Result<Vec<(String, V)>, ShellError> = record
635 .into_iter()
636 .map(|(k, v)| Ok((k, V::from_value(v)?)))
637 .collect();
638 Ok(HashMap::from_iter(items?))
639 }
640
641 fn expected_type() -> Type {
642 Type::Record(vec![].into_boxed_slice())
643 }
644}
645
646impl<T> FromValue for Box<T>
647where
648 T: FromValue,
649{
650 fn from_value(v: Value) -> Result<Self, ShellError> {
651 match T::from_value(v) {
652 Ok(val) => Ok(Box::new(val)),
653 Err(e) => Err(e),
654 }
655 }
656}
657
658impl<T> FromValue for Vec<T>
659where
660 T: FromValue,
661{
662 fn from_value(v: Value) -> Result<Self, ShellError> {
663 match v {
664 Value::List { vals, .. } => vals
665 .into_iter()
666 .map(|v| T::from_value(v))
667 .collect::<Result<Vec<T>, ShellError>>(),
668 v => Err(ShellError::CantConvert {
669 to_type: Self::expected_type().to_string(),
670 from_type: v.get_type().to_string(),
671 span: v.span(),
672 help: None,
673 }),
674 }
675 }
676
677 fn expected_type() -> Type {
678 Type::List(Box::new(T::expected_type()))
679 }
680}
681
682impl FromValue for Value {
685 fn from_value(v: Value) -> Result<Self, ShellError> {
686 Ok(v)
687 }
688
689 fn expected_type() -> Type {
690 Type::Any
691 }
692}
693
694impl FromValue for CellPath {
695 fn from_value(v: Value) -> Result<Self, ShellError> {
696 let span = v.span();
697 match v {
698 Value::CellPath { val, .. } => Ok(val),
699 Value::String { val, .. } => Ok(CellPath {
700 members: vec![PathMember::String {
701 val,
702 span,
703 optional: false,
704 casing: Casing::Sensitive,
705 }],
706 }),
707 Value::Int { val, .. } => {
708 if val.is_negative() {
709 Err(ShellError::NeedsPositiveValue { span })
710 } else {
711 Ok(CellPath {
712 members: vec![PathMember::Int {
713 val: val as usize,
714 span,
715 optional: false,
716 }],
717 })
718 }
719 }
720 x => Err(ShellError::CantConvert {
721 to_type: Self::expected_type().to_string(),
722 from_type: x.get_type().to_string(),
723 span,
724 help: None,
725 }),
726 }
727 }
728
729 fn expected_type() -> Type {
730 Type::CellPath
731 }
732}
733
734impl FromValue for Closure {
735 fn from_value(v: Value) -> Result<Self, ShellError> {
736 match v {
737 Value::Closure { val, .. } => Ok(*val),
738 v => Err(ShellError::CantConvert {
739 to_type: Self::expected_type().to_string(),
740 from_type: v.get_type().to_string(),
741 span: v.span(),
742 help: None,
743 }),
744 }
745 }
746}
747
748impl FromValue for DateTime<FixedOffset> {
749 fn from_value(v: Value) -> Result<Self, ShellError> {
750 match v {
751 Value::Date { val, .. } => Ok(val),
752 v => Err(ShellError::CantConvert {
753 to_type: Self::expected_type().to_string(),
754 from_type: v.get_type().to_string(),
755 span: v.span(),
756 help: None,
757 }),
758 }
759 }
760
761 fn expected_type() -> Type {
762 Type::Date
763 }
764}
765
766impl FromValue for NuGlob {
767 fn from_value(v: Value) -> Result<Self, ShellError> {
768 match v {
770 Value::CellPath { val, .. } => Ok(NuGlob::Expand(val.to_string())),
771 Value::String { val, .. } => Ok(NuGlob::DoNotExpand(val)),
772 Value::Glob {
773 val,
774 no_expand: quoted,
775 ..
776 } => {
777 if quoted {
778 Ok(NuGlob::DoNotExpand(val))
779 } else {
780 Ok(NuGlob::Expand(val))
781 }
782 }
783 v => Err(ShellError::CantConvert {
784 to_type: Self::expected_type().to_string(),
785 from_type: v.get_type().to_string(),
786 span: v.span(),
787 help: None,
788 }),
789 }
790 }
791
792 fn expected_type() -> Type {
793 Type::String
794 }
795}
796
797impl FromValue for Range {
798 fn from_value(v: Value) -> Result<Self, ShellError> {
799 match v {
800 Value::Range { val, .. } => Ok(*val),
801 v => Err(ShellError::CantConvert {
802 to_type: Self::expected_type().to_string(),
803 from_type: v.get_type().to_string(),
804 span: v.span(),
805 help: None,
806 }),
807 }
808 }
809
810 fn expected_type() -> Type {
811 Type::Range
812 }
813}
814
815impl FromValue for Record {
816 fn from_value(v: Value) -> Result<Self, ShellError> {
817 match v {
818 Value::Record { val, .. } => Ok(val.into_owned()),
819 v => Err(ShellError::CantConvert {
820 to_type: Self::expected_type().to_string(),
821 from_type: v.get_type().to_string(),
822 span: v.span(),
823 help: None,
824 }),
825 }
826 }
827}
828
829impl<T> FromValue for Spanned<T>
832where
833 T: FromValue,
834{
835 fn from_value(v: Value) -> Result<Self, ShellError> {
836 let span = v.span();
837 Ok(Spanned {
838 item: T::from_value(v)?,
839 span,
840 })
841 }
842
843 fn expected_type() -> Type {
844 T::expected_type()
845 }
846}
847
848impl FromValue for bytes::Bytes {
851 fn from_value(v: Value) -> Result<Self, ShellError> {
852 match v {
853 Value::Binary { val, .. } => Ok(val.into()),
854 v => Err(ShellError::CantConvert {
855 to_type: Self::expected_type().to_string(),
856 from_type: v.get_type().to_string(),
857 span: v.span(),
858 help: None,
859 }),
860 }
861 }
862
863 fn expected_type() -> Type {
864 Type::Binary
865 }
866}
867
868fn int_too_small_error(int: impl fmt::Display, min: impl fmt::Display, span: Span) -> ShellError {
870 ShellError::GenericError {
871 error: "Integer too small".to_string(),
872 msg: format!("{int} is smaller than {min}"),
873 span: Some(span),
874 help: None,
875 inner: vec![],
876 }
877}
878
879fn int_too_large_error(int: impl fmt::Display, max: impl fmt::Display, span: Span) -> ShellError {
880 ShellError::GenericError {
881 error: "Integer too large".to_string(),
882 msg: format!("{int} is larger than {max}"),
883 span: Some(span),
884 help: None,
885 inner: vec![],
886 }
887}
888
889#[cfg(test)]
890mod tests {
891 use crate::{FromValue, IntoValue, Record, Span, Type, Value, engine::Closure};
892 use std::ops::Deref;
893
894 #[test]
895 fn expected_type_default_impl() {
896 assert_eq!(
897 Record::expected_type(),
898 Type::Custom("Record".to_string().into_boxed_str())
899 );
900
901 assert_eq!(
902 Closure::expected_type(),
903 Type::Custom("Closure".to_string().into_boxed_str())
904 );
905 }
906
907 #[test]
908 fn from_value_vec_u8() {
909 let vec: Vec<u8> = vec![1, 2, 3];
910 let span = Span::test_data();
911 let string = "Hello Vec<u8>!".to_string();
912
913 assert_eq!(
914 Vec::<u8>::from_value(vec.clone().into_value(span)).unwrap(),
915 vec.clone(),
916 "Vec<u8> roundtrip"
917 );
918
919 assert_eq!(
920 Vec::<u8>::from_value(Value::test_string(string.clone()))
921 .unwrap()
922 .deref(),
923 string.as_bytes(),
924 "Vec<u8> from String"
925 );
926
927 assert_eq!(
928 Vec::<u8>::from_value(Value::test_binary(vec.clone())).unwrap(),
929 vec,
930 "Vec<u8> from Binary"
931 );
932
933 assert!(Vec::<u8>::from_value(vec![u8::MIN as i32 - 1].into_value(span)).is_err());
934 assert!(Vec::<u8>::from_value(vec![u8::MAX as i32 + 1].into_value(span)).is_err());
935 }
936}