updated docs for IntoValue and FromValue

This commit is contained in:
Tim 'Piepmatz' Hesse 2024-06-08 00:01:20 +02:00
parent f05d07239e
commit 7e7bab68f8
4 changed files with 67 additions and 29 deletions

1
Cargo.lock generated
View File

@ -3229,6 +3229,7 @@ dependencies = [
"byte-unit",
"chrono",
"chrono-humanize",
"convert_case",
"fancy-regex",
"indexmap",
"lru",

View File

@ -22,6 +22,7 @@ brotli = { workspace = true, optional = true }
byte-unit = { version = "5.1", features = [ "serde" ] }
chrono = { workspace = true, features = [ "serde", "std", "unstable-locales" ], default-features = false }
chrono-humanize = { workspace = true }
convert_case = { workspace = true }
fancy-regex = { workspace = true }
indexmap = { workspace = true }
lru = { workspace = true }

View File

@ -16,37 +16,53 @@ use std::{
///
/// # Derivable
/// This trait can be used with `#[derive]`.
/// When derived on structs with named fields, it expects a [`Value::Record`]
/// where each field of the struct maps to a corresponding field in the record.
/// For structs with unnamed fields, it expects a [`Value::List`], and the
/// fields are populated in the order they appear in the list.
/// When derived on structs with named fields, it expects a [`Value::Record`] where each field of
/// the struct maps to a corresponding field in the record.
/// For structs with unnamed fields, it expects a [`Value::List`], and the fields are populated in
/// the order they appear in the list.
/// Unit structs expect a [`Value::Nothing`], as they contain no data.
/// Attempting to convert from a non-matching `Value` type will result in an
/// error.
// TODO: explain derive for enums
/// Attempting to convert from a non-matching `Value` type will result in an error.
///
/// Only enums with no fields may derive this trait.
/// The expected value representation will be the name of the variant as a [`Value::String`].
/// By default, variant names will be expected in ["snake_case"](convert_case::Case::Snake).
/// You can customize the case conversion using `#[nu_value(rename_all = "kebab-case")]` on the enum.
/// All deterministic case conversions provided by [`convert_case::Case`] are supported by
/// specifying the case name followed by "case".
///
/// ```
/// # use nu_protocol::{FromValue, Value, ShellError};
/// #[derive(FromValue, Debug, PartialEq)]
/// #[nu_value(rename_all = "COBOL-CASE")]
/// enum Bird {
/// MountainEagle,
/// ForestOwl,
/// RiverDuck,
/// }
///
/// assert_eq!(
/// Bird::from_value(Value::test_string("RIVER-DUCK")).unwrap(),
/// Bird::RiverDuck
/// );
/// ```
pub trait FromValue: Sized {
// TODO: instead of ShellError, maybe we could have a FromValueError that implements Into<ShellError>
/// Loads a value from a [`Value`].
///
/// This method retrieves a value similarly to how strings are parsed using
/// [`FromStr`].
/// The operation might fail if the `Value` contains unexpected types or
/// structures.
/// This method retrieves a value similarly to how strings are parsed using [`FromStr`].
/// The operation might fail if the `Value` contains unexpected types or structures.
fn from_value(v: Value) -> Result<Self, ShellError>;
/// Expected `Value` type.
///
/// This is used to print out errors of what type of value is expected for
/// conversion.
/// Even if not used in [`from_value`](FromValue::from_value) this should
/// still be implemented so that other implementations like `Option` or
/// `Vec` can make use of it.
/// It is advised to call this method in `from_value` to ensure that
/// expected type in the error is consistent.
/// This is used to print out errors of what type of value is expected for conversion.
/// Even if not used in [`from_value`](FromValue::from_value) this should still be implemented
/// so that other implementations like `Option` or `Vec` can make use of it.
/// It is advised to call this method in `from_value` to ensure that expected type in the error
/// is consistent.
///
/// Unlike the default implementation, derived implementations explicitly
/// reveal the concrete type, such as [`Type::Record`] or [`Type::List`],
/// instead of an opaque type.
/// Unlike the default implementation, derived implementations explicitly reveal the concrete
/// type, such as [`Type::Record`] or [`Type::List`], instead of an opaque type.
fn expected_type() -> Type {
Type::Custom(
any::type_name::<Self>()

View File

@ -8,14 +8,34 @@ use crate::{Record, ShellError, Span, Value};
///
/// # Derivable
/// This trait can be used with `#[derive]`.
/// When derived on structs with named fields, the resulting value
/// representation will use [`Value::Record`], where each field of the record
/// corresponds to a field of the struct.
/// For structs with unnamed fields, the value representation will be
/// [`Value::List`], with all fields inserted into a list.
/// Unit structs will be represented as [`Value::Nothing`] since they contain
/// no data.
// TODO: explain derive for enums
/// When derived on structs with named fields, the resulting value representation will use
/// [`Value::Record`], where each field of the record corresponds to a field of the struct.
/// For structs with unnamed fields, the value representation will be [`Value::List`], with all
/// fields inserted into a list.
/// Unit structs will be represented as [`Value::Nothing`] since they contain no data.
///
/// Only enums with no fields may derive this trait.
/// The resulting value representation will be the name of the variant as a [`Value::String`].
/// By default, variant names will be converted to ["snake_case"](convert_case::Case::Snake).
/// You can customize the case conversion using `#[nu_value(rename_all = "kebab-case")]` on the enum.
/// All deterministic case conversions provided by [`convert_case::Case`] are supported by
/// specifying the case name followed by "case".
///
/// ```
/// # use nu_protocol::{IntoValue, Value};
/// #[derive(IntoValue)]
/// #[nu_value(rename_all = "COBOL-CASE")]
/// enum Bird {
/// MountainEagle,
/// ForestOwl,
/// RiverDuck,
/// }
///
/// assert_eq!(
/// Bird::RiverDuck.into_value_unknown(),
/// Value::test_string("RIVER-DUCK")
/// );
/// ```
pub trait IntoValue: Sized {
/// Converts the given value to a [`Value`].
fn into_value(self, span: Span) -> Value;