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
591/// This blanket implementation permits the use of [`Cow<'_, B>`] ([`Cow<'_, str>`] etc) based on
592/// the [FromValue] implementation of `B`'s owned form ([str] => [String]).
593///
594/// It's meant to make using the [FromValue] derive macro on types that contain [Cow] fields
595/// possible.
596impl<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
652// Nu Types
653
654impl 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        // FIXME: we may want to fail a little nicer here
739        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
799// Blanket Nu Implementations
800
801impl<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
818// Foreign Types
819
820impl 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
838// Use generics with `fmt::Display` to allow passing different kinds of integer
839fn 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}