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<B> FromValue for Cow<'_, B>
597where
598 B: ?Sized + ToOwned,
599 B::Owned: FromValue,
600{
601 fn from_value(v: Value) -> Result<Self, ShellError> {
602 <B::Owned as FromValue>::from_value(v).map(Cow::Owned)
603 }
604
605 fn expected_type() -> Type {
606 <B::Owned as FromValue>::expected_type()
607 }
608}
609
610impl<V> FromValue for HashMap<String, V>
611where
612 V: FromValue,
613{
614 fn from_value(v: Value) -> Result<Self, ShellError> {
615 let record = v.into_record()?;
616 let items: Result<Vec<(String, V)>, ShellError> = record
617 .into_iter()
618 .map(|(k, v)| Ok((k, V::from_value(v)?)))
619 .collect();
620 Ok(HashMap::from_iter(items?))
621 }
622
623 fn expected_type() -> Type {
624 Type::Record(vec![].into_boxed_slice())
625 }
626}
627
628impl<T> FromValue for Vec<T>
629where
630 T: FromValue,
631{
632 fn from_value(v: Value) -> Result<Self, ShellError> {
633 match v {
634 Value::List { vals, .. } => vals
635 .into_iter()
636 .map(|v| T::from_value(v))
637 .collect::<Result<Vec<T>, ShellError>>(),
638 v => Err(ShellError::CantConvert {
639 to_type: Self::expected_type().to_string(),
640 from_type: v.get_type().to_string(),
641 span: v.span(),
642 help: None,
643 }),
644 }
645 }
646
647 fn expected_type() -> Type {
648 Type::List(Box::new(T::expected_type()))
649 }
650}
651
652impl FromValue for Value {
655 fn from_value(v: Value) -> Result<Self, ShellError> {
656 Ok(v)
657 }
658
659 fn expected_type() -> Type {
660 Type::Any
661 }
662}
663
664impl FromValue for CellPath {
665 fn from_value(v: Value) -> Result<Self, ShellError> {
666 let span = v.span();
667 match v {
668 Value::CellPath { val, .. } => Ok(val),
669 Value::String { val, .. } => Ok(CellPath {
670 members: vec![PathMember::String {
671 val,
672 span,
673 optional: false,
674 casing: Casing::Sensitive,
675 }],
676 }),
677 Value::Int { val, .. } => {
678 if val.is_negative() {
679 Err(ShellError::NeedsPositiveValue { span })
680 } else {
681 Ok(CellPath {
682 members: vec![PathMember::Int {
683 val: val as usize,
684 span,
685 optional: false,
686 }],
687 })
688 }
689 }
690 x => Err(ShellError::CantConvert {
691 to_type: Self::expected_type().to_string(),
692 from_type: x.get_type().to_string(),
693 span,
694 help: None,
695 }),
696 }
697 }
698
699 fn expected_type() -> Type {
700 Type::CellPath
701 }
702}
703
704impl FromValue for Closure {
705 fn from_value(v: Value) -> Result<Self, ShellError> {
706 match v {
707 Value::Closure { val, .. } => Ok(*val),
708 v => Err(ShellError::CantConvert {
709 to_type: Self::expected_type().to_string(),
710 from_type: v.get_type().to_string(),
711 span: v.span(),
712 help: None,
713 }),
714 }
715 }
716}
717
718impl FromValue for DateTime<FixedOffset> {
719 fn from_value(v: Value) -> Result<Self, ShellError> {
720 match v {
721 Value::Date { val, .. } => Ok(val),
722 v => Err(ShellError::CantConvert {
723 to_type: Self::expected_type().to_string(),
724 from_type: v.get_type().to_string(),
725 span: v.span(),
726 help: None,
727 }),
728 }
729 }
730
731 fn expected_type() -> Type {
732 Type::Date
733 }
734}
735
736impl FromValue for NuGlob {
737 fn from_value(v: Value) -> Result<Self, ShellError> {
738 match v {
740 Value::CellPath { val, .. } => Ok(NuGlob::Expand(val.to_string())),
741 Value::String { val, .. } => Ok(NuGlob::DoNotExpand(val)),
742 Value::Glob {
743 val,
744 no_expand: quoted,
745 ..
746 } => {
747 if quoted {
748 Ok(NuGlob::DoNotExpand(val))
749 } else {
750 Ok(NuGlob::Expand(val))
751 }
752 }
753 v => Err(ShellError::CantConvert {
754 to_type: Self::expected_type().to_string(),
755 from_type: v.get_type().to_string(),
756 span: v.span(),
757 help: None,
758 }),
759 }
760 }
761
762 fn expected_type() -> Type {
763 Type::String
764 }
765}
766
767impl FromValue for Range {
768 fn from_value(v: Value) -> Result<Self, ShellError> {
769 match v {
770 Value::Range { val, .. } => Ok(*val),
771 v => Err(ShellError::CantConvert {
772 to_type: Self::expected_type().to_string(),
773 from_type: v.get_type().to_string(),
774 span: v.span(),
775 help: None,
776 }),
777 }
778 }
779
780 fn expected_type() -> Type {
781 Type::Range
782 }
783}
784
785impl FromValue for Record {
786 fn from_value(v: Value) -> Result<Self, ShellError> {
787 match v {
788 Value::Record { val, .. } => Ok(val.into_owned()),
789 v => Err(ShellError::CantConvert {
790 to_type: Self::expected_type().to_string(),
791 from_type: v.get_type().to_string(),
792 span: v.span(),
793 help: None,
794 }),
795 }
796 }
797}
798
799impl<T> FromValue for Spanned<T>
802where
803 T: FromValue,
804{
805 fn from_value(v: Value) -> Result<Self, ShellError> {
806 let span = v.span();
807 Ok(Spanned {
808 item: T::from_value(v)?,
809 span,
810 })
811 }
812
813 fn expected_type() -> Type {
814 T::expected_type()
815 }
816}
817
818impl FromValue for bytes::Bytes {
821 fn from_value(v: Value) -> Result<Self, ShellError> {
822 match v {
823 Value::Binary { val, .. } => Ok(val.into()),
824 v => Err(ShellError::CantConvert {
825 to_type: Self::expected_type().to_string(),
826 from_type: v.get_type().to_string(),
827 span: v.span(),
828 help: None,
829 }),
830 }
831 }
832
833 fn expected_type() -> Type {
834 Type::Binary
835 }
836}
837
838fn int_too_small_error(int: impl fmt::Display, min: impl fmt::Display, span: Span) -> ShellError {
840 ShellError::GenericError {
841 error: "Integer too small".to_string(),
842 msg: format!("{int} is smaller than {min}"),
843 span: Some(span),
844 help: None,
845 inner: vec![],
846 }
847}
848
849fn int_too_large_error(int: impl fmt::Display, max: impl fmt::Display, span: Span) -> ShellError {
850 ShellError::GenericError {
851 error: "Integer too large".to_string(),
852 msg: format!("{int} is larger than {max}"),
853 span: Some(span),
854 help: None,
855 inner: vec![],
856 }
857}
858
859#[cfg(test)]
860mod tests {
861 use crate::{FromValue, IntoValue, Record, Span, Type, Value, engine::Closure};
862 use std::ops::Deref;
863
864 #[test]
865 fn expected_type_default_impl() {
866 assert_eq!(
867 Record::expected_type(),
868 Type::Custom("Record".to_string().into_boxed_str())
869 );
870
871 assert_eq!(
872 Closure::expected_type(),
873 Type::Custom("Closure".to_string().into_boxed_str())
874 );
875 }
876
877 #[test]
878 fn from_value_vec_u8() {
879 let vec: Vec<u8> = vec![1, 2, 3];
880 let span = Span::test_data();
881 let string = "Hello Vec<u8>!".to_string();
882
883 assert_eq!(
884 Vec::<u8>::from_value(vec.clone().into_value(span)).unwrap(),
885 vec.clone(),
886 "Vec<u8> roundtrip"
887 );
888
889 assert_eq!(
890 Vec::<u8>::from_value(Value::test_string(string.clone()))
891 .unwrap()
892 .deref(),
893 string.as_bytes(),
894 "Vec<u8> from String"
895 );
896
897 assert_eq!(
898 Vec::<u8>::from_value(Value::test_binary(vec.clone())).unwrap(),
899 vec,
900 "Vec<u8> from Binary"
901 );
902
903 assert!(Vec::<u8>::from_value(vec![u8::MIN as i32 - 1].into_value(span)).is_err());
904 assert!(Vec::<u8>::from_value(vec![u8::MAX as i32 + 1].into_value(span)).is_err());
905 }
906}