Implement Support for no_std

This adds a new `std` feature to chrono that is enabled by default. By
deactivating this feature via `default-features = false` you can now use
chrono in applications that don't use the standard library. The `serde`
feature is supported as well.

Resolves #336
This commit is contained in:
Christopher Serr 2019-09-07 12:12:49 +02:00
parent bbfcfad44f
commit 9dc91f78ed
19 changed files with 135 additions and 63 deletions

View File

@ -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 }

11
ci/core-test/Cargo.toml Normal file
View File

@ -0,0 +1,11 @@
[package]
name = "core-test"
version = "0.1.0"
authors = [
"Kang Seonghoon <public+rust@mearie.org>",
"Brandon W Maister <quodlibetor@gmail.com>",
]
edition = "2018"
[dependencies]
chrono = { path = "../..", default-features = false, features = ["serde"] }

1
ci/core-test/src/lib.rs Normal file
View File

@ -0,0 +1 @@
#![no_std]

View File

@ -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

View File

@ -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};

View File

@ -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<Local> {
}
}
#[cfg(any(feature = "std", test))]
impl From<SystemTime> for DateTime<Utc> {
fn from(t: SystemTime) -> DateTime<Utc> {
let (sec, nsec) = match t.duration_since(UNIX_EPOCH) {
@ -672,6 +677,7 @@ impl From<SystemTime> for DateTime<Local> {
}
}
#[cfg(any(feature = "std", test))]
impl<Tz: TimeZone> From<DateTime<Tz>> for SystemTime {
fn from(dt: DateTime<Tz>) -> SystemTime {
use std::time::Duration;
@ -699,7 +705,7 @@ fn test_auto_conversion() {
fn test_encodable_json<FUtc, FFixed, E>(to_string_utc: FUtc, to_string_fixed: FFixed)
where FUtc: Fn(&DateTime<Utc>) -> Result<String, E>,
FFixed: Fn(&DateTime<FixedOffset>) -> Result<String, E>,
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<FUtc, FFixed, FLocal, E>(utc_from_str: FUtc,
where FUtc: Fn(&str) -> Result<DateTime<Utc>, E>,
FFixed: Fn(&str) -> Result<DateTime<FixedOffset>, E>,
FLocal: Fn(&str) -> Result<DateTime<Local>, 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<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> {
@ -754,7 +760,7 @@ fn test_decodable_json_timestamps<FUtc, FFixed, FLocal, E>(utc_from_str: FUtc,
where FUtc: Fn(&str) -> Result<rustc_serialize::TsSeconds<Utc>, E>,
FFixed: Fn(&str) -> Result<rustc_serialize::TsSeconds<FixedOffset>, E>,
FLocal: Fn(&str) -> Result<rustc_serialize::TsSeconds<Local>, E>,
E: ::std::fmt::Debug
E: ::core::fmt::Debug
{
fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> {
dt.as_ref().map(|dt| (dt, dt.offset()))
@ -778,8 +784,8 @@ fn test_decodable_json_timestamps<FUtc, FFixed, FLocal, E>(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};

View File

@ -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<T, ParseError>`.
pub type ParseResult<T> = Result<T, ParseError>;
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 {

View File

@ -6,7 +6,7 @@
#![allow(deprecated)]
use std::usize;
use core::usize;
use Weekday;

View File

@ -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 {

View File

@ -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<OldDuration> 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")
}

View File

@ -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;

View File

@ -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};

View File

@ -3,7 +3,7 @@
//! ISO 8601 week.
use std::fmt;
use core::fmt;
use super::internals::{DateImpl, Of, YearFlags};

View File

@ -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")
}

View File

@ -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;

View File

@ -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};

View File

@ -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;

View File

@ -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()
}
}

View File

@ -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