Skip to main content

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    shell_error::generic::GenericError,
7};
8use chrono::{DateTime, FixedOffset};
9use std::{
10    any,
11    borrow::Cow,
12    cmp::Ordering,
13    collections::{HashMap, VecDeque},
14    ffi::OsString,
15    fmt,
16    num::{
17        NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroIsize, NonZeroU16, NonZeroU32,
18        NonZeroU64, NonZeroUsize,
19    },
20    path::PathBuf,
21    str::FromStr,
22};
23
24/// A trait for loading a value from a [`Value`].
25///
26/// # Derivable
27/// This trait can be used with `#[derive]`.
28///
29/// When derived on structs with named fields, it expects a [`Value::Record`] where each field of
30/// the struct maps to a corresponding field in the record.
31///
32/// - If `#[nu_value(rename = "...")]` is applied to a field, that name will be used as the key in
33///   the record.
34/// - If `#[nu_value(rename_all = "...")]` is applied on the container (struct) the key of the
35///   field will be case-converted accordingly.
36/// - If neither attribute is applied, the field name is used as is.
37/// - If `#[nu_value(default)]` is applied to a field, the field type's [`Default`] implementation
38///   will be used if the corresponding record field is missing
39///
40/// Supported case conversions include those provided by [`heck`], such as
41/// "snake_case", "kebab-case", "PascalCase", and others.
42/// Additionally, all values accepted by
43/// [`#[serde(rename_all = "...")]`](https://serde.rs/container-attrs.html#rename_all) are valid here.
44///
45/// For structs with unnamed fields, it expects a [`Value::List`], and the fields are populated in
46/// the order they appear in the list.
47/// Unit structs expect a [`Value::Nothing`], as they contain no data.
48/// Attempting to convert from a non-matching `Value` type will result in an error.
49///
50/// Only enums with no fields may derive this trait.
51/// The expected value representation will be the name of the variant as a [`Value::String`].
52///
53/// - If `#[nu_value(rename = "...")]` is applied to a variant, that name will be used.
54/// - If `#[nu_value(rename_all = "...")]` is applied on the enum container, the name of variant
55///   will be case-converted accordingly.
56/// - If neither attribute is applied, the variant name will default to
57///   ["snake_case"](heck::ToSnakeCase).
58///
59/// Additionally, you can use `#[nu_value(type_name = "...")]` in the derive macro to set a custom type name
60/// for `FromValue::expected_type`. This will result in a `Type::Custom` with the specified type name.
61/// This can be useful in situations where the default type name is not desired.
62///
63/// # Enum Example
64/// ```
65/// # use nu_protocol::{FromValue, Value, ShellError, record, Span};
66/// #
67/// # let span = Span::unknown();
68/// #
69/// #[derive(FromValue, Debug, PartialEq)]
70/// #[nu_value(rename_all = "COBOL-CASE", type_name = "birb")]
71/// enum Bird {
72///     MountainEagle,
73///     ForestOwl,
74///     #[nu_value(rename = "RIVER-QUACK")]
75///     RiverDuck,
76/// }
77///
78/// assert_eq!(
79///     Bird::from_value(Value::string("FOREST-OWL", span)).unwrap(),
80///     Bird::ForestOwl
81/// );
82///
83/// assert_eq!(
84///     Bird::from_value(Value::string("RIVER-QUACK", span)).unwrap(),
85///     Bird::RiverDuck
86/// );
87///
88/// assert_eq!(
89///     &Bird::expected_type().to_string(),
90///     "birb"
91/// );
92/// ```
93///
94/// # Struct Example
95/// ```
96/// # use nu_protocol::{FromValue, Value, ShellError, record, Span};
97/// #
98/// # let span = Span::unknown();
99/// #
100/// #[derive(FromValue, PartialEq, Eq, Debug)]
101/// #[nu_value(rename_all = "kebab-case")]
102/// struct Person {
103///     first_name: String,
104///     last_name: String,
105///     #[nu_value(rename = "age")]
106///     age_years: u32,
107/// }
108///
109/// let value = Value::record(record! {
110///     "first-name" => Value::string("John", span),
111///     "last-name" => Value::string("Doe", span),
112///     "age" => Value::int(42, span),
113/// }, span);
114///
115/// assert_eq!(
116///     Person::from_value(value).unwrap(),
117///     Person {
118///         first_name: "John".into(),
119///         last_name: "Doe".into(),
120///         age_years: 42,
121///     }
122/// );
123/// ```
124pub trait FromValue: Sized {
125    // TODO: instead of ShellError, maybe we could have a FromValueError that implements Into<ShellError>
126    /// Loads a value from a [`Value`].
127    ///
128    /// This method retrieves a value similarly to how strings are parsed using [`FromStr`].
129    /// The operation might fail if the `Value` contains unexpected types or structures.
130    fn from_value(v: Value) -> Result<Self, ShellError>;
131
132    /// Expected `Value` type.
133    ///
134    /// This is used to print out errors of what type of value is expected for conversion.
135    /// Even if not used in [`from_value`](FromValue::from_value) this should still be implemented
136    /// so that other implementations like `Option` or `Vec` can make use of it.
137    /// It is advised to call this method in `from_value` to ensure that expected type in the error
138    /// is consistent.
139    ///
140    /// Unlike the default implementation, derived implementations explicitly reveal the concrete
141    /// type, such as [`Type::Record`] or [`Type::List`], instead of an opaque type.
142    fn expected_type() -> Type {
143        Type::Custom(
144            any::type_name::<Self>()
145                .split(':')
146                .next_back()
147                .expect("str::split returns an iterator with at least one element")
148                .to_string()
149                .into_boxed_str(),
150        )
151    }
152}
153
154// Primitive Types
155
156impl<T, const N: usize> FromValue for [T; N]
157where
158    T: FromValue,
159{
160    fn from_value(v: Value) -> Result<Self, ShellError> {
161        let span = v.span();
162        let v_ty = v.get_type();
163        let vec = Vec::<T>::from_value(v)?;
164        vec.try_into()
165            .map_err(|err_vec: Vec<T>| ShellError::CantConvert {
166                to_type: Self::expected_type().to_string(),
167                from_type: v_ty.to_string(),
168                span,
169                help: Some(match err_vec.len().cmp(&N) {
170                    Ordering::Less => format!(
171                        "input list too short ({}), expected length of {N}, add missing values",
172                        err_vec.len()
173                    ),
174                    Ordering::Equal => {
175                        unreachable!("conversion would have worked if the length would be the same")
176                    }
177                    Ordering::Greater => format!(
178                        "input list too long ({}), expected length of {N}, remove trailing values",
179                        err_vec.len()
180                    ),
181                }),
182            })
183    }
184
185    fn expected_type() -> Type {
186        Type::Custom(format!("list<{};{N}>", T::expected_type()).into_boxed_str())
187    }
188}
189
190impl FromValue for bool {
191    fn from_value(v: Value) -> Result<Self, ShellError> {
192        match v {
193            Value::Bool { val, .. } => Ok(val),
194            v => Err(ShellError::CantConvert {
195                to_type: Self::expected_type().to_string(),
196                from_type: v.get_type().to_string(),
197                span: v.span(),
198                help: None,
199            }),
200        }
201    }
202
203    fn expected_type() -> Type {
204        Type::Bool
205    }
206}
207
208impl FromValue for char {
209    fn from_value(v: Value) -> Result<Self, ShellError> {
210        let span = v.span();
211        let v_ty = v.get_type();
212        match v {
213            Value::String { ref val, .. } => match char::from_str(val) {
214                Ok(c) => Ok(c),
215                Err(_) => Err(ShellError::CantConvert {
216                    to_type: Self::expected_type().to_string(),
217                    from_type: v_ty.to_string(),
218                    span,
219                    help: Some("make the string only one char long".to_string()),
220                }),
221            },
222            _ => Err(ShellError::CantConvert {
223                to_type: Self::expected_type().to_string(),
224                from_type: v_ty.to_string(),
225                span,
226                help: None,
227            }),
228        }
229    }
230
231    fn expected_type() -> Type {
232        Type::String
233    }
234}
235
236impl FromValue for f32 {
237    fn from_value(v: Value) -> Result<Self, ShellError> {
238        f64::from_value(v).map(|float| float as f32)
239    }
240}
241
242impl FromValue for f64 {
243    fn from_value(v: Value) -> Result<Self, ShellError> {
244        match v {
245            Value::Float { val, .. } => Ok(val),
246            Value::Int { val, .. } => Ok(val as f64),
247            v => Err(ShellError::CantConvert {
248                to_type: Self::expected_type().to_string(),
249                from_type: v.get_type().to_string(),
250                span: v.span(),
251                help: None,
252            }),
253        }
254    }
255
256    fn expected_type() -> Type {
257        Type::Float
258    }
259}
260
261impl FromValue for i64 {
262    fn from_value(v: Value) -> Result<Self, ShellError> {
263        match v {
264            Value::Int { val, .. } => Ok(val),
265            Value::Duration { val, .. } => Ok(val),
266            v => Err(ShellError::CantConvert {
267                to_type: Self::expected_type().to_string(),
268                from_type: v.get_type().to_string(),
269                span: v.span(),
270                help: None,
271            }),
272        }
273    }
274
275    fn expected_type() -> Type {
276        Type::Int
277    }
278}
279
280/// This implementation supports **positive** durations only.
281impl FromValue for std::time::Duration {
282    fn from_value(v: Value) -> Result<Self, ShellError> {
283        match v {
284            Value::Duration { val, .. } => {
285                let nanos = u64::try_from(val)
286                    .map_err(|_| ShellError::NeedsPositiveValue { span: v.span() })?;
287                Ok(Self::from_nanos(nanos))
288            }
289            v => Err(ShellError::CantConvert {
290                to_type: Self::expected_type().to_string(),
291                from_type: v.get_type().to_string(),
292                span: v.span(),
293                help: None,
294            }),
295        }
296    }
297
298    fn expected_type() -> Type {
299        Type::Duration
300    }
301}
302
303//
304// We can not use impl<T: FromValue> FromValue for NonZero<T> as NonZero requires an unstable trait
305// As a result, we use this macro to implement FromValue for each NonZero type.
306//
307
308macro_rules! impl_from_value_for_nonzero {
309    ($nonzero:ty, $base:ty) => {
310        impl FromValue for $nonzero {
311            fn from_value(v: Value) -> Result<Self, ShellError> {
312                let span = v.span();
313                let val = <$base>::from_value(v)?;
314                <$nonzero>::new(val).ok_or_else(|| ShellError::IncorrectValue {
315                    msg: "use a value other than 0".into(),
316                    val_span: span,
317                    call_span: span,
318                })
319            }
320
321            fn expected_type() -> Type {
322                Type::Int
323            }
324        }
325    };
326}
327
328impl_from_value_for_nonzero!(NonZeroU16, u16);
329impl_from_value_for_nonzero!(NonZeroU32, u32);
330impl_from_value_for_nonzero!(NonZeroU64, u64);
331impl_from_value_for_nonzero!(NonZeroUsize, usize);
332
333impl_from_value_for_nonzero!(NonZeroI8, i8);
334impl_from_value_for_nonzero!(NonZeroI16, i16);
335impl_from_value_for_nonzero!(NonZeroI32, i32);
336impl_from_value_for_nonzero!(NonZeroI64, i64);
337impl_from_value_for_nonzero!(NonZeroIsize, isize);
338
339macro_rules! impl_from_value_for_int {
340    ($type:ty) => {
341        impl FromValue for $type {
342            fn from_value(v: Value) -> Result<Self, ShellError> {
343                let span = v.span();
344                let int = i64::from_value(v)?;
345                const MIN: i64 = <$type>::MIN as i64;
346                const MAX: i64 = <$type>::MAX as i64;
347                #[allow(overlapping_range_endpoints)] // calculating MIN-1 is not possible for i64::MIN
348                #[allow(unreachable_patterns)] // isize might max out i64 number range
349                <$type>::try_from(int).map_err(|_| match int {
350                    MIN..=MAX => unreachable!(
351                        "int should be within the valid range for {}",
352                        stringify!($type)
353                    ),
354                    i64::MIN..=MIN => int_too_small_error(int, <$type>::MIN, span),
355                    MAX..=i64::MAX => int_too_large_error(int, <$type>::MAX, span),
356                })
357            }
358
359            fn expected_type() -> Type {
360                i64::expected_type()
361            }
362        }
363    };
364}
365
366impl_from_value_for_int!(i8);
367impl_from_value_for_int!(i16);
368impl_from_value_for_int!(i32);
369impl_from_value_for_int!(isize);
370
371macro_rules! impl_from_value_for_uint {
372    ($type:ty, $max:expr) => {
373        impl FromValue for $type {
374            fn from_value(v: Value) -> Result<Self, ShellError> {
375                let span = v.span();
376                const MAX: i64 = $max;
377                match v {
378                    Value::Int { val, .. } | Value::Duration { val, .. } => {
379                        match val {
380                            i64::MIN..=-1 => Err(ShellError::NeedsPositiveValue { span }),
381                            0..=MAX => Ok(val as $type),
382                            #[allow(unreachable_patterns)] // u64 will max out the i64 number range
383                            n => Err(ShellError::Generic(GenericError::new(
384                                "Integer too large",
385                                format!("{n} is larger than {MAX}"),
386                                span,
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
514// `OsString` is used in flags and other uutils
515impl FromValue for OsString {
516    fn from_value(v: Value) -> Result<Self, ShellError> {
517        match v {
518            Value::String { val, .. } => Ok(OsString::from(val)),
519            Value::CellPath { val, .. } => Ok(OsString::from(val.to_string())),
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        // Using `String` here because the underlying representation is text.
531        Type::String
532    }
533}
534
535impl FromValue for String {
536    fn from_value(v: Value) -> Result<Self, ShellError> {
537        // FIXME: we may want to fail a little nicer here
538        match v {
539            Value::CellPath { val, .. } => Ok(val.to_string()),
540            Value::String { val, .. } => Ok(val),
541            v => Err(ShellError::CantConvert {
542                to_type: Self::expected_type().to_string(),
543                from_type: v.get_type().to_string(),
544                span: v.span(),
545                help: None,
546            }),
547        }
548    }
549
550    fn expected_type() -> Type {
551        Type::String
552    }
553}
554
555// This impl is different from Vec<T> as it allows reading from Value::Binary and Value::String too.
556// This also denies implementing FromValue for u8 as it would be in conflict with the Vec<T> impl.
557impl FromValue for Vec<u8> {
558    fn from_value(v: Value) -> Result<Self, ShellError> {
559        match v {
560            Value::Binary { val, .. } => Ok(val),
561            Value::String { val, .. } => Ok(val.into_bytes()),
562            Value::List { vals, .. } => {
563                const U8MIN: i64 = u8::MIN as i64;
564                const U8MAX: i64 = u8::MAX as i64;
565                let mut this = Vec::with_capacity(vals.len());
566                for val in vals {
567                    let span = val.span();
568                    let int = i64::from_value(val)?;
569                    // calculating -1 on these ranges would be less readable
570                    #[allow(overlapping_range_endpoints)]
571                    #[allow(clippy::match_overlapping_arm)]
572                    match int {
573                        U8MIN..=U8MAX => this.push(int as u8),
574                        i64::MIN..=U8MIN => return Err(int_too_small_error(int, U8MIN, span)),
575                        U8MAX..=i64::MAX => return Err(int_too_large_error(int, U8MAX, span)),
576                    };
577                }
578                Ok(this)
579            }
580            v => Err(ShellError::CantConvert {
581                to_type: Self::expected_type().to_string(),
582                from_type: v.get_type().to_string(),
583                span: v.span(),
584                help: None,
585            }),
586        }
587    }
588
589    fn expected_type() -> Type {
590        Type::Binary
591    }
592}
593
594// Blanket std Implementations
595
596impl<T> FromValue for Option<T>
597where
598    T: FromValue,
599{
600    fn from_value(v: Value) -> Result<Self, ShellError> {
601        match v {
602            Value::Nothing { .. } => Ok(None),
603            v => T::from_value(v).map(Option::Some),
604        }
605    }
606
607    fn expected_type() -> Type {
608        T::expected_type()
609    }
610}
611
612impl<A, B> FromValue for Result<A, B>
613where
614    A: FromValue,
615    B: FromValue,
616{
617    fn from_value(v: Value) -> std::result::Result<Self, ShellError> {
618        match (A::from_value(v.clone()), B::from_value(v.clone())) {
619            (Ok(a), _) => Ok(Ok(a)),
620            (_, Ok(b)) => Ok(Err(b)),
621            (Err(ea), Err(_)) => Err(ea),
622        }
623    }
624
625    fn expected_type() -> Type {
626        Type::OneOf(vec![A::expected_type(), B::expected_type()].into())
627    }
628}
629
630/// This blanket implementation permits the use of [`Cow<'_, B>`] ([`Cow<'_, str>`] etc) based on
631/// the [FromValue] implementation of `B`'s owned form ([str] => [String]).
632///
633/// It's meant to make using the [FromValue] derive macro on types that contain [Cow] fields
634/// possible.
635impl<B> FromValue for Cow<'_, B>
636where
637    B: ?Sized + ToOwned,
638    B::Owned: FromValue,
639{
640    fn from_value(v: Value) -> Result<Self, ShellError> {
641        <B::Owned as FromValue>::from_value(v).map(Cow::Owned)
642    }
643
644    fn expected_type() -> Type {
645        <B::Owned as FromValue>::expected_type()
646    }
647}
648
649impl<V> FromValue for HashMap<String, V>
650where
651    V: FromValue,
652{
653    fn from_value(v: Value) -> Result<Self, ShellError> {
654        let record = v.into_record()?;
655        let items: Result<Vec<(String, V)>, ShellError> = record
656            .into_iter()
657            .map(|(k, v)| Ok((k, V::from_value(v)?)))
658            .collect();
659        Ok(HashMap::from_iter(items?))
660    }
661
662    fn expected_type() -> Type {
663        Type::Record(vec![].into_boxed_slice())
664    }
665}
666
667impl<T> FromValue for Box<T>
668where
669    T: FromValue,
670{
671    fn from_value(v: Value) -> Result<Self, ShellError> {
672        match T::from_value(v) {
673            Ok(val) => Ok(Box::new(val)),
674            Err(e) => Err(e),
675        }
676    }
677}
678
679impl<T> FromValue for Vec<T>
680where
681    T: FromValue,
682{
683    fn from_value(v: Value) -> Result<Self, ShellError> {
684        match v {
685            Value::List { vals, .. } => vals
686                .into_iter()
687                .map(|v| T::from_value(v))
688                .collect::<Result<Vec<T>, ShellError>>(),
689            v => Err(ShellError::CantConvert {
690                to_type: Self::expected_type().to_string(),
691                from_type: v.get_type().to_string(),
692                span: v.span(),
693                help: None,
694            }),
695        }
696    }
697
698    fn expected_type() -> Type {
699        Type::List(Box::new(T::expected_type()))
700    }
701}
702
703// Nu Types
704
705impl FromValue for Value {
706    fn from_value(v: Value) -> Result<Self, ShellError> {
707        Ok(v)
708    }
709
710    fn expected_type() -> Type {
711        Type::Any
712    }
713}
714
715impl FromValue for CellPath {
716    fn from_value(v: Value) -> Result<Self, ShellError> {
717        let span = v.span();
718        match v {
719            Value::CellPath { val, .. } => Ok(val),
720            Value::String { val, .. } => Ok(CellPath {
721                members: vec![PathMember::String {
722                    val,
723                    span,
724                    optional: false,
725                    casing: Casing::Sensitive,
726                }],
727            }),
728            Value::Int { val, .. } => {
729                if val.is_negative() {
730                    Err(ShellError::NeedsPositiveValue { span })
731                } else {
732                    Ok(CellPath {
733                        members: vec![PathMember::Int {
734                            val: val as usize,
735                            span,
736                            optional: false,
737                        }],
738                    })
739                }
740            }
741            x => Err(ShellError::CantConvert {
742                to_type: Self::expected_type().to_string(),
743                from_type: x.get_type().to_string(),
744                span,
745                help: None,
746            }),
747        }
748    }
749
750    fn expected_type() -> Type {
751        Type::CellPath
752    }
753}
754
755impl FromValue for Closure {
756    fn from_value(v: Value) -> Result<Self, ShellError> {
757        match v {
758            Value::Closure { val, .. } => Ok(*val),
759            v => Err(ShellError::CantConvert {
760                to_type: Self::expected_type().to_string(),
761                from_type: v.get_type().to_string(),
762                span: v.span(),
763                help: None,
764            }),
765        }
766    }
767}
768
769impl FromValue for DateTime<FixedOffset> {
770    fn from_value(v: Value) -> Result<Self, ShellError> {
771        match v {
772            Value::Date { val, .. } => Ok(val),
773            v => Err(ShellError::CantConvert {
774                to_type: Self::expected_type().to_string(),
775                from_type: v.get_type().to_string(),
776                span: v.span(),
777                help: None,
778            }),
779        }
780    }
781
782    fn expected_type() -> Type {
783        Type::Date
784    }
785}
786
787impl FromValue for NuGlob {
788    fn from_value(v: Value) -> Result<Self, ShellError> {
789        // FIXME: we may want to fail a little nicer here
790        match v {
791            Value::CellPath { val, .. } => Ok(NuGlob::Expand(val.to_string())),
792            Value::String { val, .. } => Ok(NuGlob::DoNotExpand(val)),
793            Value::Glob {
794                val,
795                no_expand: quoted,
796                ..
797            } => {
798                if quoted {
799                    Ok(NuGlob::DoNotExpand(val))
800                } else {
801                    Ok(NuGlob::Expand(val))
802                }
803            }
804            v => Err(ShellError::CantConvert {
805                to_type: Self::expected_type().to_string(),
806                from_type: v.get_type().to_string(),
807                span: v.span(),
808                help: None,
809            }),
810        }
811    }
812
813    fn expected_type() -> Type {
814        Type::String
815    }
816}
817
818impl FromValue for Range {
819    fn from_value(v: Value) -> Result<Self, ShellError> {
820        match v {
821            Value::Range { val, .. } => Ok(*val),
822            v => Err(ShellError::CantConvert {
823                to_type: Self::expected_type().to_string(),
824                from_type: v.get_type().to_string(),
825                span: v.span(),
826                help: None,
827            }),
828        }
829    }
830
831    fn expected_type() -> Type {
832        Type::Range
833    }
834}
835
836impl FromValue for Record {
837    fn from_value(v: Value) -> Result<Self, ShellError> {
838        match v {
839            Value::Record { val, .. } => Ok(val.into_owned()),
840            v => Err(ShellError::CantConvert {
841                to_type: Self::expected_type().to_string(),
842                from_type: v.get_type().to_string(),
843                span: v.span(),
844                help: None,
845            }),
846        }
847    }
848}
849
850// Blanket Nu Implementations
851
852impl<T> FromValue for Spanned<T>
853where
854    T: FromValue,
855{
856    fn from_value(v: Value) -> Result<Self, ShellError> {
857        let span = v.span();
858        Ok(Spanned {
859            item: T::from_value(v)?,
860            span,
861        })
862    }
863
864    fn expected_type() -> Type {
865        T::expected_type()
866    }
867}
868
869// Foreign Types
870
871impl FromValue for bytes::Bytes {
872    fn from_value(v: Value) -> Result<Self, ShellError> {
873        match v {
874            Value::Binary { val, .. } => Ok(val.into()),
875            v => Err(ShellError::CantConvert {
876                to_type: Self::expected_type().to_string(),
877                from_type: v.get_type().to_string(),
878                span: v.span(),
879                help: None,
880            }),
881        }
882    }
883
884    fn expected_type() -> Type {
885        Type::Binary
886    }
887}
888
889// Use generics with `fmt::Display` to allow passing different kinds of integer
890fn int_too_small_error(int: impl fmt::Display, min: impl fmt::Display, span: Span) -> ShellError {
891    ShellError::Generic(GenericError::new(
892        "Integer too small",
893        format!("{int} is smaller than {min}"),
894        span,
895    ))
896}
897
898fn int_too_large_error(int: impl fmt::Display, max: impl fmt::Display, span: Span) -> ShellError {
899    ShellError::Generic(GenericError::new(
900        "Integer too large",
901        format!("{int} is larger than {max}"),
902        span,
903    ))
904}
905
906#[cfg(test)]
907mod tests {
908    use crate::{
909        FromValue, IntoValue, Record, Span, Type, Value,
910        ast::{CellPath, PathMember},
911        casing::Casing,
912        engine::Closure,
913    };
914    use std::ffi::OsString;
915    use std::ops::Deref;
916
917    #[test]
918    fn expected_type_default_impl() {
919        assert_eq!(
920            Record::expected_type(),
921            Type::Custom("Record".to_string().into_boxed_str())
922        );
923
924        assert_eq!(
925            Closure::expected_type(),
926            Type::Custom("Closure".to_string().into_boxed_str())
927        );
928    }
929
930    #[test]
931    fn from_value_vec_u8() {
932        let vec: Vec<u8> = vec![1, 2, 3];
933        let span = Span::test_data();
934        let string = "Hello Vec<u8>!".to_string();
935
936        assert_eq!(
937            Vec::<u8>::from_value(vec.clone().into_value(span)).unwrap(),
938            vec.clone(),
939            "Vec<u8> roundtrip"
940        );
941
942        assert_eq!(
943            Vec::<u8>::from_value(Value::test_string(string.clone()))
944                .unwrap()
945                .deref(),
946            string.as_bytes(),
947            "Vec<u8> from String"
948        );
949
950        assert_eq!(
951            Vec::<u8>::from_value(Value::test_binary(vec.clone())).unwrap(),
952            vec,
953            "Vec<u8> from Binary"
954        );
955
956        assert!(Vec::<u8>::from_value(vec![u8::MIN as i32 - 1].into_value(span)).is_err());
957        assert!(Vec::<u8>::from_value(vec![u8::MAX as i32 + 1].into_value(span)).is_err());
958    }
959
960    #[test]
961    fn from_value_os_string() {
962        let span = Span::test_data();
963        let expected = OsString::from("hello");
964
965        // simple string
966        assert_eq!(
967            OsString::from_value(Value::test_string("hello".to_string())).unwrap(),
968            expected
969        );
970
971        // cell path is treated as a string via `CellPath::to_string` which includes
972        // the leading `$.`.  This matches the behaviour of `String::from_value`.
973        let cp_val = Value::test_cell_path(CellPath {
974            members: vec![PathMember::String {
975                val: "hello".into(),
976                span,
977                optional: false,
978                casing: Casing::Sensitive,
979            }],
980        });
981        assert_eq!(
982            OsString::from_value(cp_val).unwrap(),
983            OsString::from("$.hello")
984        );
985    }
986}