diff --git a/Cargo.toml b/Cargo.toml index 5185872..7893ecb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,17 +24,17 @@ appveyor = { repository = "chronotope/chrono" } name = "chrono" [features] -default = ["clock"] -clock = ["time"] +default = ["clock", "std"] +std = [] +clock = ["time", "std"] wasmbind = ["wasm-bindgen", "js-sys"] [dependencies] -libc = { version = "0.2", default-features = false } 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", 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/ci/core-test/Cargo.toml b/ci/core-test/Cargo.toml new file mode 100644 index 0000000..ad75e16 --- /dev/null +++ b/ci/core-test/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "core-test" +version = "0.1.0" +authors = [ + "Kang Seonghoon ", + "Brandon W Maister ", +] +edition = "2018" + +[dependencies] +chrono = { path = "../..", default-features = false, features = ["serde"] } diff --git a/ci/core-test/src/lib.rs b/ci/core-test/src/lib.rs new file mode 100644 index 0000000..0c9ac1a --- /dev/null +++ b/ci/core-test/src/lib.rs @@ -0,0 +1 @@ +#![no_std] diff --git a/ci/travis.sh b/ci/travis.sh index 98e25ce..809f234 100755 --- a/ci/travis.sh +++ b/ci/travis.sh @@ -85,6 +85,13 @@ build_only() { channel build -v --no-default-features } +build_core_test() { + rustup target add thumbv6m-none-eabi --toolchain $CHANNEL + cd ci/core-test + channel build -v --target thumbv6m-none-eabi + cd ../.. +} + run_clippy() { # cached installation will not work on a later nightly if [ -n "${TRAVIS}" ] && ! cargo install clippy --debug --force; then @@ -119,3 +126,6 @@ build_and_test CHANNEL=1.13.0 build_only + +CHANNEL=stable +build_core_test diff --git a/src/date.rs b/src/date.rs index f8b59ce..a6e5ab8 100644 --- a/src/date.rs +++ b/src/date.rs @@ -3,9 +3,9 @@ //! ISO 8601 calendar date with time zone. -use std::{fmt, hash}; -use std::cmp::Ordering; -use std::ops::{Add, Sub}; +use core::{fmt, hash}; +use core::cmp::Ordering; +use core::ops::{Add, Sub}; use oldtime::Duration as OldDuration; use {Weekday, Datelike}; diff --git a/src/datetime.rs b/src/datetime.rs index b4881bf..75a6922 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -3,12 +3,16 @@ //! ISO 8601 date and time with time zone. -use std::{str, fmt, hash}; -use std::cmp::Ordering; -use std::ops::{Add, Sub}; +use core::{str, fmt, hash}; +use core::cmp::Ordering; +use core::ops::{Add, Sub}; +#[cfg(any(feature = "std", test))] use std::time::{SystemTime, UNIX_EPOCH}; use oldtime::Duration as OldDuration; +#[cfg(not(any(feature = "std", test)))] +use alloc::string::{String, ToString}; + use {Weekday, Timelike, Datelike}; #[cfg(feature="clock")] use offset::Local; @@ -647,6 +651,7 @@ impl str::FromStr for DateTime { } } +#[cfg(any(feature = "std", test))] impl From for DateTime { fn from(t: SystemTime) -> DateTime { let (sec, nsec) = match t.duration_since(UNIX_EPOCH) { @@ -672,6 +677,7 @@ impl From for DateTime { } } +#[cfg(any(feature = "std", test))] impl From> for SystemTime { fn from(dt: DateTime) -> SystemTime { use std::time::Duration; @@ -699,7 +705,7 @@ fn test_auto_conversion() { fn test_encodable_json(to_string_utc: FUtc, to_string_fixed: FFixed) where FUtc: Fn(&DateTime) -> Result, FFixed: Fn(&DateTime) -> Result, - E: ::std::fmt::Debug + E: ::core::fmt::Debug { assert_eq!(to_string_utc(&Utc.ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(), Some(r#""2014-07-24T12:34:06Z""#.into())); @@ -717,7 +723,7 @@ fn test_decodable_json(utc_from_str: FUtc, where FUtc: Fn(&str) -> Result, E>, FFixed: Fn(&str) -> Result, E>, FLocal: Fn(&str) -> Result, E>, - E: ::std::fmt::Debug + E: ::core::fmt::Debug { // should check against the offset as well (the normal DateTime comparison will ignore them) fn norm(dt: &Option>) -> Option<(&DateTime, &Tz::Offset)> { @@ -754,7 +760,7 @@ fn test_decodable_json_timestamps(utc_from_str: FUtc, where FUtc: Fn(&str) -> Result, E>, FFixed: Fn(&str) -> Result, E>, FLocal: Fn(&str) -> Result, E>, - E: ::std::fmt::Debug + E: ::core::fmt::Debug { fn norm(dt: &Option>) -> Option<(&DateTime, &Tz::Offset)> { dt.as_ref().map(|dt| (dt, dt.offset())) @@ -778,8 +784,8 @@ fn test_decodable_json_timestamps(utc_from_str: FUtc, #[cfg(feature = "rustc-serialize")] pub mod rustc_serialize { - use std::fmt; - use std::ops::Deref; + use core::fmt; + use core::ops::Deref; use super::DateTime; #[cfg(feature="clock")] use offset::Local; @@ -907,7 +913,9 @@ pub mod rustc_serialize { /// documented at re-export site #[cfg(feature = "serde")] pub mod serde { - use std::fmt; + use core::fmt; + #[cfg(not(any(feature = "std", test)))] + use alloc::format; use super::DateTime; #[cfg(feature="clock")] use offset::Local; @@ -967,7 +975,7 @@ pub mod serde { /// # fn main() { example().unwrap(); } /// ``` pub mod ts_nanoseconds { - use std::fmt; + use core::fmt; use serdelib::{ser, de}; use {DateTime, Utc}; @@ -1114,7 +1122,7 @@ pub mod serde { /// # fn main() { example().unwrap(); } /// ``` pub mod ts_milliseconds { - use std::fmt; + use core::fmt; use serdelib::{ser, de}; use {DateTime, Utc}; @@ -1261,7 +1269,7 @@ pub mod serde { /// # fn main() { example().unwrap(); } /// ``` pub mod ts_seconds { - use std::fmt; + use core::fmt; use serdelib::{ser, de}; use {DateTime, Utc}; diff --git a/src/format/mod.rs b/src/format/mod.rs index 24647b4..e4e6776 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -17,9 +17,13 @@ #![allow(ellipsis_inclusive_range_patterns)] -use std::fmt; -use std::str::FromStr; +use core::fmt; +use core::str::FromStr; +#[cfg(any(feature = "std", test))] use std::error::Error; +use alloc::boxed::Box; +#[cfg(not(any(feature = "std", test)))] +use alloc::string::{String, ToString}; use {Datelike, Timelike, Weekday, ParseWeekdayError}; use div::{div_floor, mod_floor}; @@ -30,7 +34,7 @@ pub use self::strftime::StrftimeItems; pub use self::parsed::Parsed; pub use self::parse::parse; -/// An unhabitated type used for `InternalNumeric` and `InternalFixed` below. +/// An uninhabited type used for `InternalNumeric` and `InternalFixed` below. #[derive(Clone, PartialEq, Eq)] enum Void {} @@ -55,7 +59,7 @@ pub enum Pad { /// /// The **parsing width** is the maximal width to be scanned. /// The parser only tries to consume from one to given number of digits (greedily). -/// It also trims the preceding whitespaces if any. +/// It also trims the preceding whitespace if any. /// It cannot parse the negative number, so some date and time cannot be formatted then /// parsed with the same formatting items. #[derive(Clone, PartialEq, Eq, Debug)] @@ -185,13 +189,13 @@ pub enum Fixed { TimezoneName, /// Offset from the local time to UTC (`+09:00` or `-04:00` or `+00:00`). /// - /// In the parser, the colon can be omitted and/or surrounded with any amount of whitespaces. + /// In the parser, the colon can be omitted and/or surrounded with any amount of whitespace. /// The offset is limited from `-24:00` to `+24:00`, /// which is same to [`FixedOffset`](../offset/struct.FixedOffset.html)'s range. TimezoneOffsetColon, /// Offset from the local time to UTC (`+09:00` or `-04:00` or `Z`). /// - /// In the parser, the colon can be omitted and/or surrounded with any amount of whitespaces, + /// In the parser, the colon can be omitted and/or surrounded with any amount of whitespace, /// and `Z` can be either in upper case or in lower case. /// The offset is limited from `-24:00` to `+24:00`, /// which is same to [`FixedOffset`](../offset/struct.FixedOffset.html)'s range. @@ -305,13 +309,7 @@ enum ParseErrorKind { /// Same to `Result`. pub type ParseResult = Result; -impl fmt::Display for ParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.description().fmt(f) - } -} - -impl Error for ParseError { +impl ParseError { fn description(&self) -> &str { match self.0 { ParseErrorKind::OutOfRange => "input is out of range", @@ -325,6 +323,19 @@ impl Error for ParseError { } } +impl fmt::Display for ParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + +#[cfg(any(feature = "std", test))] +impl Error for ParseError { + fn description(&self) -> &str { + self.description() + } +} + // to be used in this module and submodules const OUT_OF_RANGE: ParseError = ParseError(ParseErrorKind::OutOfRange); const IMPOSSIBLE: ParseError = ParseError(ParseErrorKind::Impossible); @@ -356,7 +367,7 @@ pub fn format<'a, I>( static LONG_WEEKDAYS: [&'static str; 7] = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]; - use std::fmt::Write; + use core::fmt::Write; let mut result = String::new(); for item in items { diff --git a/src/format/parse.rs b/src/format/parse.rs index 01e326e..c10a802 100644 --- a/src/format/parse.rs +++ b/src/format/parse.rs @@ -6,7 +6,7 @@ #![allow(deprecated)] -use std::usize; +use core::usize; use Weekday; diff --git a/src/lib.rs b/src/lib.rs index b43fa0d..704f3b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -387,6 +387,8 @@ #![deny(missing_docs)] #![deny(missing_debug_implementations)] +#![cfg_attr(not(any(feature = "std", test)), no_std)] + // The explicit 'static lifetimes are still needed for rustc 1.13-16 // backward compatibility, and this appeases clippy. If minimum rustc // becomes 1.17, should be able to remove this, those 'static lifetimes, @@ -403,6 +405,13 @@ trivially_copy_pass_by_ref, ))] +#[cfg(not(any(feature = "std", test)))] +extern crate alloc; +#[cfg(any(feature = "std", test))] +extern crate std as core; +#[cfg(any(feature = "std", test))] +extern crate std as alloc; + #[cfg(feature="clock")] extern crate time as oldtime; extern crate num_integer; @@ -678,7 +687,7 @@ impl num_traits::FromPrimitive for Weekday { } } -use std::fmt; +use core::fmt; /// An error resulting from reading `Weekday` value with `FromStr`. #[derive(Clone, PartialEq)] @@ -697,7 +706,9 @@ impl fmt::Debug for ParseWeekdayError { #[cfg(feature = "serde")] mod weekday_serde { use super::Weekday; - use std::fmt; + use core::fmt; + #[cfg(not(any(feature = "std", test)))] + use alloc::format; use serdelib::{ser, de}; impl ser::Serialize for Weekday { diff --git a/src/naive/date.rs b/src/naive/date.rs index aad98bc..f429597 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -3,8 +3,8 @@ //! ISO 8601 calendar date without timezone. -use std::{str, fmt}; -use std::ops::{Add, Sub, AddAssign, SubAssign}; +use core::{str, fmt}; +use core::ops::{Add, Sub, AddAssign, SubAssign}; use num_traits::ToPrimitive; use oldtime::Duration as OldDuration; @@ -1387,7 +1387,7 @@ impl SubAssign for NaiveDate { /// Subtracts another `NaiveDate` from the current date. /// Returns a `Duration` of integral numbers. -/// +/// /// This does not overflow or underflow at all, /// as all possible output fits in the range of `Duration`. /// @@ -1600,7 +1600,9 @@ mod rustc_serialize { #[cfg(feature = "serde")] mod serde { - use std::fmt; + use core::fmt; + #[cfg(not(any(feature = "std", test)))] + use alloc::format; use super::NaiveDate; use serdelib::{ser, de}; @@ -1629,7 +1631,7 @@ mod serde { impl<'de> de::Visitor<'de> for NaiveDateVisitor { type Value = NaiveDate; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "a formatted date string") } diff --git a/src/naive/datetime.rs b/src/naive/datetime.rs index bb9ff8d..6f4fbe7 100644 --- a/src/naive/datetime.rs +++ b/src/naive/datetime.rs @@ -3,8 +3,8 @@ //! ISO 8601 date and time without timezone. -use std::{str, fmt, hash}; -use std::ops::{Add, Sub, AddAssign, SubAssign}; +use core::{str, fmt, hash}; +use core::ops::{Add, Sub, AddAssign, SubAssign}; use num_traits::ToPrimitive; use oldtime::Duration as OldDuration; @@ -1663,7 +1663,9 @@ pub mod rustc_serialize { /// Tools to help serializing/deserializing `NaiveDateTime`s #[cfg(feature = "serde")] pub mod serde { - use std::fmt; + use core::fmt; + #[cfg(not(any(feature = "std", test)))] + use alloc::format; use super::{NaiveDateTime}; use serdelib::{ser, de}; @@ -1750,7 +1752,9 @@ pub mod serde { /// # fn main() { example().unwrap(); } /// ``` pub mod ts_nanoseconds { - use std::fmt; + use core::fmt; + #[cfg(not(any(feature = "std", test)))] + use alloc::format; use serdelib::{ser, de}; use NaiveDateTime; @@ -1895,7 +1899,9 @@ pub mod serde { /// # fn main() { example().unwrap(); } /// ``` pub mod ts_milliseconds { - use std::fmt; + use core::fmt; + #[cfg(not(any(feature = "std", test)))] + use alloc::format; use serdelib::{ser, de}; use NaiveDateTime; @@ -2040,7 +2046,9 @@ pub mod serde { /// # fn main() { example().unwrap(); } /// ``` pub mod ts_seconds { - use std::fmt; + use core::fmt; + #[cfg(not(any(feature = "std", test)))] + use alloc::format; use serdelib::{ser, de}; use NaiveDateTime; diff --git a/src/naive/internals.rs b/src/naive/internals.rs index dd9d535..a1cd1f6 100644 --- a/src/naive/internals.rs +++ b/src/naive/internals.rs @@ -15,7 +15,7 @@ #![allow(dead_code)] // some internal methods have been left for consistency -use std::{i32, fmt}; +use core::{i32, fmt}; use num_traits::FromPrimitive; use Weekday; use div::{div_rem, mod_floor}; diff --git a/src/naive/isoweek.rs b/src/naive/isoweek.rs index 667cf2f..0aeedb0 100644 --- a/src/naive/isoweek.rs +++ b/src/naive/isoweek.rs @@ -3,7 +3,7 @@ //! ISO 8601 week. -use std::fmt; +use core::fmt; use super::internals::{DateImpl, Of, YearFlags}; diff --git a/src/naive/time.rs b/src/naive/time.rs index 440c8a7..c1cf297 100644 --- a/src/naive/time.rs +++ b/src/naive/time.rs @@ -3,8 +3,8 @@ //! ISO 8601 time without timezone. -use std::{str, fmt, hash}; -use std::ops::{Add, Sub, AddAssign, SubAssign}; +use core::{str, fmt, hash}; +use core::ops::{Add, Sub, AddAssign, SubAssign}; use oldtime::Duration as OldDuration; use Timelike; @@ -681,7 +681,7 @@ impl NaiveTime { // `rhs.frac`|========================================>| // | | | `self - rhs` | | - use std::cmp::Ordering; + use core::cmp::Ordering; let secs = i64::from(self.secs) - i64::from(rhs.secs); let frac = i64::from(self.frac) - i64::from(rhs.frac); @@ -1411,7 +1411,9 @@ mod rustc_serialize { #[cfg(feature = "serde")] mod serde { - use std::fmt; + use core::fmt; + #[cfg(not(any(feature = "std", test)))] + use alloc::format; use super::NaiveTime; use serdelib::{ser, de}; @@ -1431,7 +1433,7 @@ mod serde { impl<'de> de::Visitor<'de> for NaiveTimeVisitor { type Value = NaiveTime; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "a formatted time string") } diff --git a/src/offset/fixed.rs b/src/offset/fixed.rs index 5b69ef0..01512c0 100644 --- a/src/offset/fixed.rs +++ b/src/offset/fixed.rs @@ -3,8 +3,8 @@ //! The time zone which has a fixed offset from UTC. -use std::ops::{Add, Sub}; -use std::fmt; +use core::ops::{Add, Sub}; +use core::fmt; use oldtime::Duration as OldDuration; use Timelike; diff --git a/src/offset/mod.rs b/src/offset/mod.rs index 566e427..a255292 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -18,7 +18,7 @@ //! and provides implementations for 1 and 3. //! An `TimeZone` instance can be reconstructed from the corresponding `Offset` instance. -use std::fmt; +use core::fmt; use format::{parse, ParseResult, Parsed, StrftimeItems}; use naive::{NaiveDate, NaiveDateTime, NaiveTime}; diff --git a/src/offset/utc.rs b/src/offset/utc.rs index 87a4fba..da8de11 100644 --- a/src/offset/utc.rs +++ b/src/offset/utc.rs @@ -3,7 +3,7 @@ //! The UTC (Coordinated Universal Time) time zone. -use std::fmt; +use core::fmt; #[cfg(all(feature="clock", not(all(target_arch = "wasm32", feature = "wasmbind"))))] use oldtime; diff --git a/src/oldtime.rs b/src/oldtime.rs index 2bdc2f6..d523b54 100644 --- a/src/oldtime.rs +++ b/src/oldtime.rs @@ -10,10 +10,11 @@ //! Temporal quantification -use std::{fmt, i64}; +use core::{fmt, i64}; +#[cfg(any(feature = "std", test))] use std::error::Error; -use std::ops::{Add, Sub, Mul, Div, Neg}; -use std::time::Duration as StdDuration; +use core::ops::{Add, Sub, Mul, Div, Neg}; +use core::time::Duration as StdDuration; /// The number of nanoseconds in a microsecond. const NANOS_PER_MICRO: i32 = 1000; @@ -392,15 +393,22 @@ impl fmt::Display for Duration { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct OutOfRangeError(()); +impl OutOfRangeError { + fn description(&self) -> &str { + "Source duration value is out of range for the target type" + } +} + impl fmt::Display for OutOfRangeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) } } +#[cfg(any(feature = "std", test))] impl Error for OutOfRangeError { fn description(&self) -> &str { - "Source duration value is out of range for the target type" + self.description() } } diff --git a/src/round.rs b/src/round.rs index bf62762..ac5b984 100644 --- a/src/round.rs +++ b/src/round.rs @@ -2,7 +2,7 @@ // See README.md and LICENSE.txt for details. use Timelike; -use std::ops::{Add, Sub}; +use core::ops::{Add, Sub}; use oldtime::Duration; /// Extension trait for subsecond rounding or truncation to a maximum number