From 89de54e3b9c17009c4a4f69ed2df91e6c744048d Mon Sep 17 00:00:00 2001 From: Chris Hanks Date: Sun, 6 Feb 2022 17:59:44 -0700 Subject: [PATCH 1/9] Add a Display variant to Value. --- valuable/src/value.rs | 51 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/valuable/src/value.rs b/valuable/src/value.rs index 2db9cd1..37bb62f 100644 --- a/valuable/src/value.rs +++ b/valuable/src/value.rs @@ -1,6 +1,7 @@ use crate::{Enumerable, Listable, Mappable, Structable, Tuplable, Valuable, Visit}; use core::fmt; +use std::fmt::Display; macro_rules! value { ( @@ -65,6 +66,27 @@ macro_rules! value { $variant($ty), )* + /// An arbitrary value that implements Display. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// use valuable::{Value, Valuable}; + /// + /// struct Meters(u32); + /// + /// impl fmt::Display for Meters { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "{}m", self.0) + /// } + /// } + /// + /// let meters = Meters(5); + /// let v = Value::Display(&meters); + /// ``` + Display(&'a dyn Display), + /// A Rust `()` or `None` value. /// /// # Examples @@ -104,6 +126,7 @@ macro_rules! value { $(#[$attrs])* $variant(v) => fmt::Debug::fmt(v, fmt), )* + Display(d) => d.fmt(fmt), Unit => ().fmt(fmt), } } @@ -690,6 +713,34 @@ macro_rules! convert { _ => None, } } + + /// Return a `&dyn Display` representation of `self`, if possible. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// use valuable::{Value, Valuable}; + /// + /// struct Meters(u32); + /// + /// impl fmt::Display for Meters { + /// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// write!(f, "{}m", self.0) + /// } + /// } + /// + /// let meters = Meters(5); + /// + /// assert!(Value::Display(&meters).as_display().is_some()); + /// assert!(Value::Bool(true).as_display().is_none()); + /// ``` + pub fn as_display(&self) -> Option<&dyn Display> { + match *self { + Value::Display(v) => Some(v), + _ => None, + } + } } } } From c23e6322d7b4014851544ea767f9f6e89831b812 Mon Sep 17 00:00:00 2001 From: Chris Hanks Date: Sun, 6 Feb 2022 18:03:58 -0700 Subject: [PATCH 2/9] Use Display from core, rather than std. --- valuable/src/value.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/valuable/src/value.rs b/valuable/src/value.rs index 37bb62f..d155287 100644 --- a/valuable/src/value.rs +++ b/valuable/src/value.rs @@ -1,7 +1,6 @@ use crate::{Enumerable, Listable, Mappable, Structable, Tuplable, Valuable, Visit}; use core::fmt; -use std::fmt::Display; macro_rules! value { ( @@ -85,7 +84,7 @@ macro_rules! value { /// let meters = Meters(5); /// let v = Value::Display(&meters); /// ``` - Display(&'a dyn Display), + Display(&'a dyn fmt::Display), /// A Rust `()` or `None` value. /// @@ -735,7 +734,7 @@ macro_rules! convert { /// assert!(Value::Display(&meters).as_display().is_some()); /// assert!(Value::Bool(true).as_display().is_none()); /// ``` - pub fn as_display(&self) -> Option<&dyn Display> { + pub fn as_display(&self) -> Option<&dyn fmt::Display> { match *self { Value::Display(v) => Some(v), _ => None, From 08f7adb9d7a965a703b22b3d54abe681606ba0fe Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 3 Mar 2022 09:47:20 -0800 Subject: [PATCH 3/9] add `From<&'a dyn Display>` for `Value` Signed-off-by: Eliza Weisman --- valuable/src/value.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/valuable/src/value.rs b/valuable/src/value.rs index d155287..4630a99 100644 --- a/valuable/src/value.rs +++ b/valuable/src/value.rs @@ -113,6 +113,12 @@ macro_rules! value { } } + impl<'a> From<&'a dyn fmt::Display> for Value<'a> { + fn from(src: &'a dyn fmt::Display) -> Self { + Self::Display(src) + } + } + impl fmt::Debug for Value<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { use Value::*; From b6adbd6bdde74023c888ce80edc8dddeae1e9fd6 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 3 Mar 2022 09:54:52 -0800 Subject: [PATCH 4/9] handle other variants in `Value::as_display` Signed-off-by: Eliza Weisman --- valuable/src/value.rs | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/valuable/src/value.rs b/valuable/src/value.rs index 4630a99..6a781e0 100644 --- a/valuable/src/value.rs +++ b/valuable/src/value.rs @@ -721,6 +721,12 @@ macro_rules! convert { /// Return a `&dyn Display` representation of `self`, if possible. /// + /// If this value is a [`Value::Display`] variant, or any primitive + /// `Value` variant, this method will return a `&dyn Display` trait + /// object. Otherwise, if the value is [`Structable`], + /// [`Enumerable`], [`Tupleable`], [`Listable`], [`Mappable`], or a + /// [`Value::Path`], this method will return `None`. + /// /// # Examples /// /// ``` @@ -738,11 +744,40 @@ macro_rules! convert { /// let meters = Meters(5); /// /// assert!(Value::Display(&meters).as_display().is_some()); - /// assert!(Value::Bool(true).as_display().is_none()); + /// assert!(Value::Tupleable((true, "hello")).as_display().is_none()); /// ``` pub fn as_display(&self) -> Option<&dyn fmt::Display> { + use Value::*; match *self { - Value::Display(v) => Some(v), + I8(ref v) => Some(v), + I16(ref v) => Some(v), + I32(ref v) => Some(v), + I64(ref v) => Some(v), + I128(ref v) => Some(v), + Isize(ref v) => Some(v), + U8(ref v) => Some(v), + U16(ref v) => Some(v), + U32(ref v) => Some(v), + U64(ref v) => Some(v), + U128(ref v) => Some(v), + Usize(ref v) => Some(v), + F32(ref v) => Some(v), + F64(ref v) => Some(v), + Bool(ref v) => Some(v), + Char(ref v) => Some(v), + String(ref v) => Some(v), + + #[cfg(feature = "std")] + Error(ref v) => Some(v), + + // XXX(eliza): this, sadly, does not work for `Path`s; the + // only way to return them as a `Display` impl is + // `Path::display`, which creates a value owned by _this_ + // function; we can't return that as a trait object because + // we're borrowing it from the function's scope rather than + // from the value itself. + + Display(v) => Some(v), _ => None, } } From 3b983db3db9b6fd898a9fa63e29a181a4837dae3 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 3 Mar 2022 09:56:31 -0800 Subject: [PATCH 5/9] quote `Display` values in `Debug` impl This indicates that `Display` values are essentially being recorded as strings, rather than structured data, in the `Debug` output. Signed-off-by: Eliza Weisman --- valuable/src/value.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/valuable/src/value.rs b/valuable/src/value.rs index 6a781e0..d1dafaf 100644 --- a/valuable/src/value.rs +++ b/valuable/src/value.rs @@ -131,7 +131,7 @@ macro_rules! value { $(#[$attrs])* $variant(v) => fmt::Debug::fmt(v, fmt), )* - Display(d) => d.fmt(fmt), + Display(d) => write!(fmt, "\"{}\"", d), Unit => ().fmt(fmt), } } From 3b1abd64686728fb987dca3159c87165b8a9728b Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 3 Mar 2022 09:57:38 -0800 Subject: [PATCH 6/9] serde: serialize `Display` values Signed-off-by: Eliza Weisman --- valuable-serde/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/valuable-serde/src/lib.rs b/valuable-serde/src/lib.rs index 73d53d4..480be1f 100644 --- a/valuable-serde/src/lib.rs +++ b/valuable-serde/src/lib.rs @@ -265,6 +265,7 @@ where Value::Path(p) => Serialize::serialize(p, serializer), #[cfg(feature = "std")] Value::Error(e) => Err(S::Error::custom(e)), + Value::Display(d) => serializer.collect_str(d), v => unimplemented!("{:?}", v), } From 4212a91e9413513b2b5579b7ffe431870d73bfe1 Mon Sep 17 00:00:00 2001 From: Chris Hanks Date: Tue, 8 Mar 2022 14:53:13 -0500 Subject: [PATCH 7/9] Update valuable/src/value.rs Co-authored-by: Eliza Weisman --- valuable/src/value.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/valuable/src/value.rs b/valuable/src/value.rs index d1dafaf..fac0d73 100644 --- a/valuable/src/value.rs +++ b/valuable/src/value.rs @@ -65,7 +65,7 @@ macro_rules! value { $variant($ty), )* - /// An arbitrary value that implements Display. + /// An arbitrary value that implements [`std::fmt::Display`]. /// /// # Examples /// From 61bb35bd52b6dc6fb0efabfaa0eff27700672e80 Mon Sep 17 00:00:00 2001 From: Chris Hanks Date: Tue, 8 Mar 2022 14:56:25 -0500 Subject: [PATCH 8/9] Tupleable -> Tuplable --- valuable/src/value.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/valuable/src/value.rs b/valuable/src/value.rs index fac0d73..7aee12a 100644 --- a/valuable/src/value.rs +++ b/valuable/src/value.rs @@ -724,7 +724,7 @@ macro_rules! convert { /// If this value is a [`Value::Display`] variant, or any primitive /// `Value` variant, this method will return a `&dyn Display` trait /// object. Otherwise, if the value is [`Structable`], - /// [`Enumerable`], [`Tupleable`], [`Listable`], [`Mappable`], or a + /// [`Enumerable`], [`Tuplable`], [`Listable`], [`Mappable`], or a /// [`Value::Path`], this method will return `None`. /// /// # Examples @@ -744,7 +744,7 @@ macro_rules! convert { /// let meters = Meters(5); /// /// assert!(Value::Display(&meters).as_display().is_some()); - /// assert!(Value::Tupleable((true, "hello")).as_display().is_none()); + /// assert!(Value::Tuplable((true, "hello")).as_display().is_none()); /// ``` pub fn as_display(&self) -> Option<&dyn fmt::Display> { use Value::*; From 2f57fb35b1d0d4fb4b8efdfea37e8b72f23c3fd7 Mon Sep 17 00:00:00 2001 From: Chris Hanks Date: Tue, 8 Mar 2022 15:46:26 -0500 Subject: [PATCH 9/9] Fix doctest failure. --- valuable/src/value.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/valuable/src/value.rs b/valuable/src/value.rs index 7aee12a..deeabf1 100644 --- a/valuable/src/value.rs +++ b/valuable/src/value.rs @@ -744,7 +744,7 @@ macro_rules! convert { /// let meters = Meters(5); /// /// assert!(Value::Display(&meters).as_display().is_some()); - /// assert!(Value::Tuplable((true, "hello")).as_display().is_none()); + /// assert!(Value::Tuplable(&(true, "hello")).as_display().is_none()); /// ``` pub fn as_display(&self) -> Option<&dyn fmt::Display> { use Value::*;