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