From e5bbc94c3bcd7406cca33502bb73a7a50ab127a6 Mon Sep 17 00:00:00 2001 From: Brandon W Maister Date: Sun, 15 Sep 2019 20:45:49 -0400 Subject: [PATCH] First pass at making "alloc" its own feature Part of this means that we don't actually need to allocate to write to Serde any more, which is a win in its own right. --- Cargo.toml | 4 +++- src/datetime.rs | 46 +++++++++++++++++++++++++++++++++---------- src/format/mod.rs | 4 ++-- src/lib.rs | 22 ++++++++++++++++----- src/naive/date.rs | 10 ++++++++-- src/naive/datetime.rs | 2 +- src/naive/time.rs | 2 +- 7 files changed, 68 insertions(+), 22 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 58392f7..5135032 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,8 @@ name = "chrono" default = ["clock", "std"] alloc = [] std = [] +serde_alloc = ["serde/alloc"] +serde_std = ["serde/std"] clock = ["time", "std"] wasmbind = ["wasm-bindgen", "js-sys"] @@ -35,7 +37,7 @@ time = { version = "0.1.39", optional = true } num-integer = { version = "0.1.36", default-features = false } num-traits = { version = "0.2", default-features = false } rustc-serialize = { version = "0.3.20", optional = true } -serde = { version = "1.0.99", default-features = false, features = ["alloc"], optional = true } +serde = { version = "1.0.99", default-features = false, optional = true } [target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies] wasm-bindgen = { version = "0.2", optional = true } diff --git a/src/datetime.rs b/src/datetime.rs index 99bd316..092da60 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -10,8 +10,10 @@ use core::ops::{Add, Sub}; use std::time::{SystemTime, UNIX_EPOCH}; use oldtime::Duration as OldDuration; -#[cfg(any(feature = "alloc", feature = "std", test))] +#[cfg(all(not(feature = "std"), feature = "alloc"))] use alloc::string::{String, ToString}; +#[cfg(feature = "std")] +use std::string::ToString; use {Weekday, Timelike, Datelike}; #[cfg(feature="clock")] @@ -921,26 +923,50 @@ pub mod rustc_serialize { #[cfg(feature = "serde")] pub mod serde { use core::fmt; - #[cfg(not(any(feature = "std", test)))] - use alloc::format; + // #[cfg(any(test, feature = "alloc"))] + // use alloc::format; use super::DateTime; #[cfg(feature="clock")] use offset::Local; use offset::{LocalResult, TimeZone, Utc, FixedOffset}; use serdelib::{ser, de}; + enum SerdeError { + NonExistent { timestamp: V }, + Ambiguous { timestamp: V, min: D, max: D } + } + + impl fmt::Debug for SerdeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "ChronoSerdeError({})", self) + } + } + + // impl core::error::Error for SerdeError {} + impl fmt::Display for SerdeError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &SerdeError::NonExistent { ref timestamp } => write!( + f, "value is not a legal timestamp: {}", timestamp), + &SerdeError::Ambiguous { ref timestamp, ref min, ref max } => write!( + f, "value is an ambiguous timestamp: {}, could be either of {}, {}", + timestamp, min, max), + } + } + } + // try!-like function to convert a LocalResult into a serde-ish Result fn serde_from(me: LocalResult, ts: &V) -> Result - where E: de::Error, - V: fmt::Display, - T: fmt::Display, + where + E: de::Error, + V: fmt::Display, + T: fmt::Display, { match me { LocalResult::None => Err(E::custom( - format!("value is not a legal timestamp: {}", ts))), + SerdeError::NonExistent::<_, u8> { timestamp: ts })), LocalResult::Ambiguous(min, max) => Err(E::custom( - format!("value is an ambiguous timestamp: {}, could be either of {}, {}", - ts, min, max))), + SerdeError::Ambiguous { timestamp: ts, min: min, max: max })), LocalResult::Single(val) => Ok(val) } } @@ -1418,7 +1444,7 @@ pub mod serde { fn visit_str(self, value: &str) -> Result, E> where E: de::Error { - value.parse().map_err(|err| E::custom(format!("{}", err))) + value.parse().map_err(|err: ::format::ParseError| E::custom(err)) } } diff --git a/src/format/mod.rs b/src/format/mod.rs index fb05c93..e003c30 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -21,9 +21,9 @@ use core::fmt; use core::str::FromStr; #[cfg(any(feature = "std", test))] use std::error::Error; -#[cfg(any(feature = "alloc", feature = "std", test))] +#[cfg(feature = "alloc")] use alloc::boxed::Box; -#[cfg(any(feature = "alloc", feature = "std", test))] +#[cfg(feature = "alloc")] use alloc::string::{String, ToString}; #[cfg(not(any(feature = "alloc", feature = "std", test)))] diff --git a/src/lib.rs b/src/lib.rs index 704f3b0..ad6710c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -405,11 +405,11 @@ trivially_copy_pass_by_ref, ))] -#[cfg(not(any(feature = "std", test)))] +#[cfg(feature = "alloc")] extern crate alloc; #[cfg(any(feature = "std", test))] extern crate std as core; -#[cfg(any(feature = "std", test))] +#[cfg(all(feature = "std", not(feature="alloc")))] extern crate std as alloc; #[cfg(feature="clock")] @@ -654,6 +654,20 @@ impl Weekday { } } +impl fmt::Display for Weekday { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str(match *self { + Weekday::Mon => "Mon", + Weekday::Tue => "Tue", + Weekday::Wed => "Wed", + Weekday::Thu => "Thu", + Weekday::Fri => "Fri", + Weekday::Sat => "Sat", + Weekday::Sun => "Sun", + }) + } +} + /// Any weekday can be represented as an integer from 0 to 6, which equals to /// [`Weekday::num_days_from_monday`](#method.num_days_from_monday) in this implementation. /// Do not heavily depend on this though; use explicit methods whenever possible. @@ -707,15 +721,13 @@ impl fmt::Debug for ParseWeekdayError { mod weekday_serde { use super::Weekday; use core::fmt; - #[cfg(not(any(feature = "std", test)))] - use alloc::format; use serdelib::{ser, de}; impl ser::Serialize for Weekday { fn serialize(&self, serializer: S) -> Result where S: ser::Serializer { - serializer.serialize_str(&format!("{:?}", self)) + serializer.collect_str(&self) } } diff --git a/src/naive/date.rs b/src/naive/date.rs index eecf84b..cbd1350 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -1605,8 +1605,6 @@ mod rustc_serialize { #[cfg(feature = "serde")] mod serde { use core::fmt; - #[cfg(not(any(feature = "std", test)))] - use alloc::format; use super::NaiveDate; use serdelib::{ser, de}; @@ -1640,11 +1638,19 @@ mod serde { write!(formatter, "a formatted date string") } + #[cfg(any(feature = "std", test))] fn visit_str(self, value: &str) -> Result where E: de::Error { value.parse().map_err(|err| E::custom(format!("{}", err))) } + + #[cfg(not(any(feature = "std", test)))] + fn visit_str(self, value: &str) -> Result + where E: de::Error + { + value.parse().map_err(|err| E::custom(err)) + } } impl<'de> de::Deserialize<'de> for NaiveDate { diff --git a/src/naive/datetime.rs b/src/naive/datetime.rs index 9d93b2f..60e2a77 100644 --- a/src/naive/datetime.rs +++ b/src/naive/datetime.rs @@ -1668,7 +1668,7 @@ pub mod rustc_serialize { #[cfg(feature = "serde")] pub mod serde { use core::fmt; - #[cfg(not(any(feature = "std", test)))] + #[cfg(feature = "alloc")] use alloc::format; use super::{NaiveDateTime}; use serdelib::{ser, de}; diff --git a/src/naive/time.rs b/src/naive/time.rs index 71379e7..45b2643 100644 --- a/src/naive/time.rs +++ b/src/naive/time.rs @@ -1416,7 +1416,7 @@ mod rustc_serialize { #[cfg(feature = "serde")] mod serde { use core::fmt; - #[cfg(not(any(feature = "std", test)))] + #[cfg(feature = "alloc")] use alloc::format; use super::NaiveTime; use serdelib::{ser, de};