nu_protocol/value/
from_value.rs

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
22/// A trait for loading a value from a [`Value`].
23///
24/// # Derivable
25/// This trait can be used with `#[derive]`.
26///
27/// When derived on structs with named fields, it expects a [`Value::Record`] where each field of
28/// the struct maps to a corresponding field in the record.
29///
30/// - If `#[nu_value(rename = "...")]` is applied to a field, that name will be used as the key in
31///   the record.
32/// - If `#[nu_value(rename_all = "...")]` is applied on the container (struct) the key of the
33///   field will be case-converted accordingly.
34/// - If neither attribute is applied, the field name is used as is.
35/// - If `#[nu_value(default)]` is applied to a field, the field type's [`Default`] implementation
36///   will be used if the corresponding record field is missing
37///
38/// Supported case conversions include those provided by [`heck`], such as
39/// "snake_case", "kebab-case", "PascalCase", and others.
40/// Additionally, all values accepted by
41/// [`#[serde(rename_all = "...")]`](https://serde.rs/container-attrs.html#rename_all) are valid here.
42///
43/// For structs with unnamed fields, it expects a [`Value::List`], and the fields are populated in
44/// the order they appear in the list.
45/// Unit structs expect a [`Value::Nothing`], as they contain no data.
46/// Attempting to convert from a non-matching `Value` type will result in an error.
47///
48/// Only enums with no fields may derive this trait.
49/// The expected value representation will be the name of the variant as a [`Value::String`].
50///
51/// - If `#[nu_value(rename = "...")]` is applied to a variant, that name will be used.
52/// - If `#[nu_value(rename_all = "...")]` is applied on the enum container, the name of variant
53///   will be case-converted accordingly.
54/// - If neither attribute is applied, the variant name will default to
55///   ["snake_case"](heck::ToSnakeCase).
56///
57/// Additionally, you can use `#[nu_value(type_name = "...")]` in the derive macro to set a custom type name
58/// for `FromValue::expected_type`. This will result in a `Type::Custom` with the specified type name.
59/// This can be useful in situations where the default type name is not desired.
60///
61/// # Enum Example
62/// ```
63/// # use nu_protocol::{FromValue, Value, ShellError, record, Span};
64/// #
65/// # let span = Span::unknown();
66/// #
67/// #[derive(FromValue, Debug, PartialEq)]
68/// #[nu_value(rename_all = "COBOL-CASE", type_name = "birb")]
69/// enum Bird {
70///     MountainEagle,
71///     ForestOwl,
72///     #[nu_value(rename = "RIVER-QUACK")]
73///     RiverDuck,
74/// }
75///
76/// assert_eq!(
77///     Bird::from_value(Value::string("FOREST-OWL", span)).unwrap(),
78///     Bird::ForestOwl
79/// );
80///
81/// assert_eq!(
82///     Bird::from_value(Value::string("RIVER-QUACK", span)).unwrap(),
83///     Bird::RiverDuck
84/// );
85///
86/// assert_eq!(
87///     &Bird::expected_type().to_string(),
88///     "birb"
89/// );
90/// ```
91///
92/// # Struct Example
93/// ```
94/// # use nu_protocol::{FromValue, Value, ShellError, record, Span};
95/// #
96/// # let span = Span::unknown();
97/// #
98/// #[derive(FromValue, PartialEq, Eq, Debug)]
99/// #[nu_value(rename_all = "kebab-case")]
100/// struct Person {
101///     first_name: String,
102///     last_name: String,
103///     #[nu_value(rename = "age")]
104///     age_years: u32,
105/// }
106///
107/// let value = Value::record(record! {
108///     "first-name" => Value::string("John", span),
109///     "last-name" => Value::string("Doe", span),
110///     "age" => Value::int(42, span),
111/// }, span);
112///
113/// assert_eq!(
114///     Person::from_value(value).unwrap(),
115///     Person {
116///         first_name: "John".into(),
117///         last_name: "Doe".into(),
118///         age_years: 42,
119///     }
120/// );
121/// ```
122pub trait FromValue: Sized {
123    // TODO: instead of ShellError, maybe we could have a FromValueError that implements Into<ShellError>
124    /// Loads a value from a [`Value`].
125    ///
126    /// This method retrieves a value similarly to how strings are parsed using [`FromStr`].
127    /// The operation might fail if the `Value` contains unexpected types or structures.
128    fn from_value(v: Value) -> Result<Self, ShellError>;
129
130    /// Expected `Value` type.
131    ///
132    /// This is used to print out errors of what type of value is expected for conversion.
133    /// Even if not used in [`from_value`](FromValue::from_value) this should still be implemented
134    /// so that other implementations like `Option` or `Vec` can make use of it.
135    /// It is advised to call this method in `from_value` to ensure that expected type in the error
136    /// is consistent.
137    ///
138    /// Unlike the default implementation, derived implementations explicitly reveal the concrete
139    /// type, such as [`Type::Record`] or [`Type::List`], instead of an opaque type.
140    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
152// Primitive Types
153
154impl<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
278/// This implementation supports **positive** durations only.
279impl 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
301//
302// We can not use impl<T: FromValue> FromValue for NonZero<T> as NonZero requires an unstable trait
303// As a result, we use this macro to implement FromValue for each NonZero type.
304//
305
306macro_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)] // calculating MIN-1 is not possible for i64::MIN
346                #[allow(unreachable_patterns)] // isize might max out i64 number range
347                <$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)] // u64 will max out the i64 number range
381                            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
406// Sadly we cannot implement FromValue for u8 without losing the impl of Vec<u8>,
407// Rust would find two possible implementations then, Vec<u8> and Vec<T = u8>,
408// and wouldn't compile.
409// The blanket implementation for Vec<T> is probably more useful than
410// implementing FromValue for u8.
411
412impl_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); // u64::Max would be -1 as i64
415#[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
480// Tuples in std are implemented for up to 12 elements, so we do it here too.
481tuple_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
494// Other std Types
495
496impl 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        // FIXME: we may want to fail a little nicer here
517        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
534// This impl is different from Vec<T> as it allows reading from Value::Binary and Value::String too.
535// This also denies implementing FromValue for u8 as it would be in conflict with the Vec<T> impl.
536impl 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                    // calculating -1 on these ranges would be less readable
549                    #[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
573// Blanket std Implementations
574
575impl<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
609/// This blanket implementation permits the use of [`Cow<'_, B>`] ([`Cow<'_, str>`] etc) based on
610/// the [FromValue] implementation of `B`'s owned form ([str] => [String]).
611///
612/// It's meant to make using the [FromValue] derive macro on types that contain [Cow] fields
613/// possible.
614impl<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
682// Nu Types
683
684impl 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        // FIXME: we may want to fail a little nicer here
769        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
829// Blanket Nu Implementations
830
831impl<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
848// Foreign Types
849
850impl 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
868// Use generics with `fmt::Display` to allow passing different kinds of integer
869fn 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}