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