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", "byte-unit",
"chrono", "chrono",
"chrono-humanize", "chrono-humanize",
"convert_case",
"fancy-regex", "fancy-regex",
"indexmap", "indexmap",
"lru", "lru",

View File

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

View File

@ -16,37 +16,53 @@ use std::{
/// ///
/// # Derivable /// # Derivable
/// This trait can be used with `#[derive]`. /// This trait can be used with `#[derive]`.
/// When derived on structs with named fields, it expects a [`Value::Record`] /// When derived on structs with named fields, it expects a [`Value::Record`] where each field of
/// where each field of the struct maps to a corresponding field in the record. /// the struct maps to a corresponding field in the record.
/// For structs with unnamed fields, it expects a [`Value::List`], and the /// For structs with unnamed fields, it expects a [`Value::List`], and the fields are populated in
/// fields are populated in the order they appear in the list. /// the order they appear in the list.
/// Unit structs expect a [`Value::Nothing`], as they contain no data. /// Unit structs expect a [`Value::Nothing`], as they contain no data.
/// Attempting to convert from a non-matching `Value` type will result in an /// Attempting to convert from a non-matching `Value` type will result in an error.
/// error. ///
// TODO: explain derive for enums /// 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 { pub trait FromValue: Sized {
// TODO: instead of ShellError, maybe we could have a FromValueError that implements Into<ShellError> // TODO: instead of ShellError, maybe we could have a FromValueError that implements Into<ShellError>
/// Loads a value from a [`Value`]. /// Loads a value from a [`Value`].
/// ///
/// This method retrieves a value similarly to how strings are parsed using /// This method retrieves a value similarly to how strings are parsed using [`FromStr`].
/// [`FromStr`]. /// The operation might fail if the `Value` contains unexpected types or structures.
/// The operation might fail if the `Value` contains unexpected types or
/// structures.
fn from_value(v: Value) -> Result<Self, ShellError>; fn from_value(v: Value) -> Result<Self, ShellError>;
/// Expected `Value` type. /// Expected `Value` type.
/// ///
/// This is used to print out errors of what type of value is expected for /// This is used to print out errors of what type of value is expected for conversion.
/// conversion. /// Even if not used in [`from_value`](FromValue::from_value) this should still be implemented
/// Even if not used in [`from_value`](FromValue::from_value) this should /// so that other implementations like `Option` or `Vec` can make use of it.
/// still be implemented so that other implementations like `Option` or /// It is advised to call this method in `from_value` to ensure that expected type in the error
/// `Vec` can make use of it. /// is consistent.
/// 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 /// Unlike the default implementation, derived implementations explicitly reveal the concrete
/// reveal the concrete type, such as [`Type::Record`] or [`Type::List`], /// type, such as [`Type::Record`] or [`Type::List`], instead of an opaque type.
/// instead of an opaque type.
fn expected_type() -> Type { fn expected_type() -> Type {
Type::Custom( Type::Custom(
any::type_name::<Self>() any::type_name::<Self>()

View File

@ -8,14 +8,34 @@ use crate::{Record, ShellError, Span, Value};
/// ///
/// # Derivable /// # Derivable
/// This trait can be used with `#[derive]`. /// This trait can be used with `#[derive]`.
/// When derived on structs with named fields, the resulting value /// When derived on structs with named fields, the resulting value representation will use
/// representation will use [`Value::Record`], where each field of the record /// [`Value::Record`], where each field of the record corresponds to a field of the struct.
/// corresponds to a field of the struct. /// For structs with unnamed fields, the value representation will be [`Value::List`], with all
/// For structs with unnamed fields, the value representation will be /// fields inserted into a list.
/// [`Value::List`], with all fields inserted into a list. /// Unit structs will be represented as [`Value::Nothing`] since they contain no data.
/// Unit structs will be represented as [`Value::Nothing`] since they contain ///
/// no data. /// Only enums with no fields may derive this trait.
// TODO: explain derive for enums /// 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 { pub trait IntoValue: Sized {
/// Converts the given value to a [`Value`]. /// Converts the given value to a [`Value`].
fn into_value(self, span: Span) -> Value; fn into_value(self, span: Span) -> Value;