From a9a05350a9421f928d94efba684b6318767b3eb7 Mon Sep 17 00:00:00 2001 From: Anthony Ramine Date: Sun, 26 Feb 2017 15:02:15 +0100 Subject: [PATCH 1/6] Introduce Serializer::collect_str (fixes #786) The default implementation collects the Display value into a String and then passes that to Serializer::serialize_str when the std or collections features are enabled, otherwise it unconditionally returns an error. --- serde/src/ser/mod.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index 38f9ec7b..f69ab635 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -98,7 +98,11 @@ use std::error; #[cfg(not(feature = "std"))] use error; +#[cfg(all(feature = "collections", not(feature = "std")))] +use collections::string::String; use core::fmt::Display; +#[cfg(any(feature = "std", feature = "collections"))] +use core::fmt::Write; use core::iter::IntoIterator; mod impls; @@ -616,6 +620,29 @@ pub trait Serializer: Sized { } serializer.end() } + + /// Collect a `Display` value as a string. + /// + /// The default implementation serializes the given value as a string with + /// `ToString::to_string`. + #[cfg(any(feature = "std", feature = "collections"))] + fn collect_str(self, value: &T) -> Result + where T: Display, + { + let mut string = String::new(); + write!(string, "{}", value).unwrap(); + self.serialize_str(&string) + } + + /// Collect a `Display` value as a string. + /// + /// The default implementation returns an error unconditionally. + #[cfg(not(any(feature = "std", feature = "collections")))] + fn collect_str(self, _value: &T) -> Result + where T: Display, + { + Err(Error::custom("Default impl of collect_str errors out for no_std builds")) + } } /// Returned from `Serializer::serialize_seq` and From 880b27b19ed3eb208ddfdcb8e0128a0b7aea20f7 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 5 Mar 2017 16:17:03 -0800 Subject: [PATCH 2/6] Identical signature for std and no_std collect_str --- serde/src/ser/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index f69ab635..e12e5998 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -638,7 +638,7 @@ pub trait Serializer: Sized { /// /// The default implementation returns an error unconditionally. #[cfg(not(any(feature = "std", feature = "collections")))] - fn collect_str(self, _value: &T) -> Result + fn collect_str(self, _value: &T) -> Result where T: Display, { Err(Error::custom("Default impl of collect_str errors out for no_std builds")) From fbe85f399d907087cf1098937d8639159419353a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 5 Mar 2017 16:22:02 -0800 Subject: [PATCH 3/6] Force no_std formats to implement collect_str in the future --- serde/src/ser/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index e12e5998..3cc87d4e 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -641,6 +641,8 @@ pub trait Serializer: Sized { fn collect_str(self, _value: &T) -> Result where T: Display, { + // TODO https://github.com/serde-rs/serde/issues/805 + // Remove this impl and force no_std formats to implement collect_str. Err(Error::custom("Default impl of collect_str errors out for no_std builds")) } } From 36da8a5cee13b0d34a652b3231f2f62d10abaec6 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 5 Mar 2017 16:24:42 -0800 Subject: [PATCH 4/6] Error message geared toward serializer users The previous message was targeted toward Serializer implementors, which is not the group that will be seeing this message most often. --- serde/src/ser/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index 3cc87d4e..02c43657 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -643,7 +643,7 @@ pub trait Serializer: Sized { { // TODO https://github.com/serde-rs/serde/issues/805 // Remove this impl and force no_std formats to implement collect_str. - Err(Error::custom("Default impl of collect_str errors out for no_std builds")) + Err(Error::custom("this no_std format does not support serializing strings with collect_str")) } } From 7e1b5c6ce431cfca4387c0148e9a07afc27bab13 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 5 Mar 2017 16:26:05 -0800 Subject: [PATCH 5/6] Neater collect_str variable name for rustdoc --- serde/src/ser/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index 02c43657..ec3a72c6 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -638,11 +638,12 @@ pub trait Serializer: Sized { /// /// The default implementation returns an error unconditionally. #[cfg(not(any(feature = "std", feature = "collections")))] - fn collect_str(self, _value: &T) -> Result + fn collect_str(self, value: &T) -> Result where T: Display, { // TODO https://github.com/serde-rs/serde/issues/805 // Remove this impl and force no_std formats to implement collect_str. + let _ = value; Err(Error::custom("this no_std format does not support serializing strings with collect_str")) } } From 2184fef82f0d1c5ce3a953f3c96ce4b6c2568c43 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 5 Mar 2017 16:43:31 -0800 Subject: [PATCH 6/6] Add format_args example to collect_str --- serde/src/ser/mod.rs | 48 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/serde/src/ser/mod.rs b/serde/src/ser/mod.rs index ec3a72c6..f91db459 100644 --- a/serde/src/ser/mod.rs +++ b/serde/src/ser/mod.rs @@ -621,10 +621,29 @@ pub trait Serializer: Sized { serializer.end() } - /// Collect a `Display` value as a string. + /// Serialize a string produced by an implementation of `Display`. /// - /// The default implementation serializes the given value as a string with - /// `ToString::to_string`. + /// The default implementation builds a heap-allocated `String` and + /// delegates to `serialize_str`. Serializers are encouraged to provide a + /// more efficient implementation if possible. + /// + /// ```rust + /// # use serde::{Serialize, Serializer}; + /// # struct DateTime; + /// # impl DateTime { + /// # fn naive_local(&self) -> () { () } + /// # fn offset(&self) -> () { () } + /// # } + /// impl Serialize for DateTime { + /// fn serialize(&self, serializer: S) -> Result + /// where S: Serializer + /// { + /// serializer.collect_str(&format_args!("{:?}{:?}", + /// self.naive_local(), + /// self.offset())) + /// } + /// } + /// ``` #[cfg(any(feature = "std", feature = "collections"))] fn collect_str(self, value: &T) -> Result where T: Display, @@ -634,9 +653,28 @@ pub trait Serializer: Sized { self.serialize_str(&string) } - /// Collect a `Display` value as a string. + /// Serialize a string produced by an implementation of `Display`. /// - /// The default implementation returns an error unconditionally. + /// The default implementation returns an error unconditionally when + /// compiled with `no_std`. + /// + /// ```rust + /// # use serde::{Serialize, Serializer}; + /// # struct DateTime; + /// # impl DateTime { + /// # fn naive_local(&self) -> () { () } + /// # fn offset(&self) -> () { () } + /// # } + /// impl Serialize for DateTime { + /// fn serialize(&self, serializer: S) -> Result + /// where S: Serializer + /// { + /// serializer.collect_str(&format_args!("{:?}{:?}", + /// self.naive_local(), + /// self.offset())) + /// } + /// } + /// ``` #[cfg(not(any(feature = "std", feature = "collections")))] fn collect_str(self, value: &T) -> Result where T: Display,