Skip to content

Commit

Permalink
Remove dependency on num-traits
Browse files Browse the repository at this point in the history
Co-authored-by: Dirkjan Ochtman <[email protected]>
  • Loading branch information
esheppa and djc committed Aug 27, 2022
1 parent f14e07d commit 77f5eed
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 104 deletions.
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ __doctest = []

[dependencies]
num-integer = { version = "0.1.36", default-features = false }
num-traits = { version = "0.2", default-features = false }
serde = { version = "1.0.99", default-features = false, optional = true }
pure-rust-locales = { version = "0.5.2", optional = true }
criterion = { version = "0.3", optional = true }
Expand Down
43 changes: 25 additions & 18 deletions src/format/parsed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
//! A collection of parsed date and time items.
//! They can be constructed incrementally while being checked for consistency.
use core::convert::TryFrom;

use num_integer::div_rem;
use num_traits::ToPrimitive;

use super::{ParseResult, IMPOSSIBLE, NOT_ENOUGH, OUT_OF_RANGE};
use crate::naive::{NaiveDate, NaiveDateTime, NaiveTime};
Expand Down Expand Up @@ -134,7 +135,7 @@ impl Parsed {
/// Tries to set the [`year`](#structfield.year) field from given value.
#[inline]
pub fn set_year(&mut self, value: i64) -> ParseResult<()> {
set_if_consistent(&mut self.year, value.to_i32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(&mut self.year, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
}

/// Tries to set the [`year_div_100`](#structfield.year_div_100) field from given value.
Expand All @@ -143,7 +144,7 @@ impl Parsed {
if value < 0 {
return Err(OUT_OF_RANGE);
}
set_if_consistent(&mut self.year_div_100, value.to_i32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(&mut self.year_div_100, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
}

/// Tries to set the [`year_mod_100`](#structfield.year_mod_100) field from given value.
Expand All @@ -152,13 +153,13 @@ impl Parsed {
if value < 0 {
return Err(OUT_OF_RANGE);
}
set_if_consistent(&mut self.year_mod_100, value.to_i32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(&mut self.year_mod_100, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
}

/// Tries to set the [`isoyear`](#structfield.isoyear) field from given value.
#[inline]
pub fn set_isoyear(&mut self, value: i64) -> ParseResult<()> {
set_if_consistent(&mut self.isoyear, value.to_i32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(&mut self.isoyear, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
}

/// Tries to set the [`isoyear_div_100`](#structfield.isoyear_div_100) field from given value.
Expand All @@ -167,7 +168,10 @@ impl Parsed {
if value < 0 {
return Err(OUT_OF_RANGE);
}
set_if_consistent(&mut self.isoyear_div_100, value.to_i32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(
&mut self.isoyear_div_100,
i32::try_from(value).map_err(|_| OUT_OF_RANGE)?,
)
}

/// Tries to set the [`isoyear_mod_100`](#structfield.isoyear_mod_100) field from given value.
Expand All @@ -176,31 +180,34 @@ impl Parsed {
if value < 0 {
return Err(OUT_OF_RANGE);
}
set_if_consistent(&mut self.isoyear_mod_100, value.to_i32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(
&mut self.isoyear_mod_100,
i32::try_from(value).map_err(|_| OUT_OF_RANGE)?,
)
}

/// Tries to set the [`month`](#structfield.month) field from given value.
#[inline]
pub fn set_month(&mut self, value: i64) -> ParseResult<()> {
set_if_consistent(&mut self.month, value.to_u32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(&mut self.month, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
}

/// Tries to set the [`week_from_sun`](#structfield.week_from_sun) field from given value.
#[inline]
pub fn set_week_from_sun(&mut self, value: i64) -> ParseResult<()> {
set_if_consistent(&mut self.week_from_sun, value.to_u32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(&mut self.week_from_sun, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
}

/// Tries to set the [`week_from_mon`](#structfield.week_from_mon) field from given value.
#[inline]
pub fn set_week_from_mon(&mut self, value: i64) -> ParseResult<()> {
set_if_consistent(&mut self.week_from_mon, value.to_u32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(&mut self.week_from_mon, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
}

/// Tries to set the [`isoweek`](#structfield.isoweek) field from given value.
#[inline]
pub fn set_isoweek(&mut self, value: i64) -> ParseResult<()> {
set_if_consistent(&mut self.isoweek, value.to_u32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(&mut self.isoweek, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
}

/// Tries to set the [`weekday`](#structfield.weekday) field from given value.
Expand All @@ -212,13 +219,13 @@ impl Parsed {
/// Tries to set the [`ordinal`](#structfield.ordinal) field from given value.
#[inline]
pub fn set_ordinal(&mut self, value: i64) -> ParseResult<()> {
set_if_consistent(&mut self.ordinal, value.to_u32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(&mut self.ordinal, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
}

/// Tries to set the [`day`](#structfield.day) field from given value.
#[inline]
pub fn set_day(&mut self, value: i64) -> ParseResult<()> {
set_if_consistent(&mut self.day, value.to_u32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(&mut self.day, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
}

/// Tries to set the [`hour_div_12`](#structfield.hour_div_12) field from given value.
Expand All @@ -242,7 +249,7 @@ impl Parsed {
/// [`hour_mod_12`](#structfield.hour_mod_12) fields from given value.
#[inline]
pub fn set_hour(&mut self, value: i64) -> ParseResult<()> {
let v = value.to_u32().ok_or(OUT_OF_RANGE)?;
let v = u32::try_from(value).map_err(|_| OUT_OF_RANGE)?;
set_if_consistent(&mut self.hour_div_12, v / 12)?;
set_if_consistent(&mut self.hour_mod_12, v % 12)?;
Ok(())
Expand All @@ -251,19 +258,19 @@ impl Parsed {
/// Tries to set the [`minute`](#structfield.minute) field from given value.
#[inline]
pub fn set_minute(&mut self, value: i64) -> ParseResult<()> {
set_if_consistent(&mut self.minute, value.to_u32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(&mut self.minute, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
}

/// Tries to set the [`second`](#structfield.second) field from given value.
#[inline]
pub fn set_second(&mut self, value: i64) -> ParseResult<()> {
set_if_consistent(&mut self.second, value.to_u32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(&mut self.second, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
}

/// Tries to set the [`nanosecond`](#structfield.nanosecond) field from given value.
#[inline]
pub fn set_nanosecond(&mut self, value: i64) -> ParseResult<()> {
set_if_consistent(&mut self.nanosecond, value.to_u32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(&mut self.nanosecond, u32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
}

/// Tries to set the [`timestamp`](#structfield.timestamp) field from given value.
Expand All @@ -275,7 +282,7 @@ impl Parsed {
/// Tries to set the [`offset`](#structfield.offset) field from given value.
#[inline]
pub fn set_offset(&mut self, value: i64) -> ParseResult<()> {
set_if_consistent(&mut self.offset, value.to_i32().ok_or(OUT_OF_RANGE)?)
set_if_consistent(&mut self.offset, i32::try_from(value).map_err(|_| OUT_OF_RANGE)?)
}

/// Returns a parsed naive date out of given fields.
Expand Down
28 changes: 28 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@
#![cfg_attr(docsrs, feature(doc_cfg))]

mod oldtime;
use core::fmt;

#[cfg(feature = "__doctest")]
#[cfg_attr(feature = "__doctest", cfg(doctest))]
Expand Down Expand Up @@ -508,6 +509,33 @@ pub mod serde {
pub use super::datetime::serde::*;
}

/// Out of range error type used in various converting APIs
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct OutOfRange {
_private: (),
}

impl OutOfRange {
fn new() -> OutOfRange {
OutOfRange { _private: () }
}
}

impl fmt::Display for OutOfRange {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "out of range")
}
}

impl fmt::Debug for OutOfRange {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "out of range")
}
}

#[cfg(feature = "std")]
impl std::error::Error for OutOfRange {}

/// MSRV 1.42
#[cfg(test)]
#[macro_export]
Expand Down
81 changes: 32 additions & 49 deletions src/month.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
use core::fmt;
use core::{convert::TryFrom, fmt};

#[cfg(feature = "rkyv")]
use rkyv::{Archive, Deserialize, Serialize};

use crate::OutOfRange;

/// The month of the year.
///
/// This enum is just a convenience implementation.
/// The month in dates created by DateLike objects does not return this enum.
///
/// It is possible to convert from a date to a month independently
/// ```
/// use num_traits::FromPrimitive;
/// use chrono::prelude::*;
/// use std::convert::TryFrom;
/// let date = Utc.ymd(2019, 10, 28).and_hms(9, 10, 11);
/// // `2019-10-28T09:10:11Z`
/// let month = Month::from_u32(date.month());
/// let month = Month::try_from(u8::try_from(date.month()).unwrap()).ok();
/// assert_eq!(month, Some(Month::October))
/// ```
/// Or from a Month to an integer usable by dates
Expand Down Expand Up @@ -151,39 +153,24 @@ impl Month {
}
}

impl num_traits::FromPrimitive for Month {
/// Returns an Option<Month> from a i64, assuming a 1-index, January = 1.
///
/// `Month::from_i64(n: i64)`: | `1` | `2` | ... | `12`
/// ---------------------------| -------------------- | --------------------- | ... | -----
/// ``: | Some(Month::January) | Some(Month::February) | ... | Some(Month::December)
#[inline]
fn from_u64(n: u64) -> Option<Month> {
Self::from_u32(n as u32)
}

#[inline]
fn from_i64(n: i64) -> Option<Month> {
Self::from_u32(n as u32)
}

#[inline]
fn from_u32(n: u32) -> Option<Month> {
match n {
1 => Some(Month::January),
2 => Some(Month::February),
3 => Some(Month::March),
4 => Some(Month::April),
5 => Some(Month::May),
6 => Some(Month::June),
7 => Some(Month::July),
8 => Some(Month::August),
9 => Some(Month::September),
10 => Some(Month::October),
11 => Some(Month::November),
12 => Some(Month::December),
_ => None,
impl TryFrom<u8> for Month {
type Error = OutOfRange;

fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
1 => Ok(Month::January),
2 => Ok(Month::February),
3 => Ok(Month::March),
4 => Ok(Month::April),
5 => Ok(Month::May),
6 => Ok(Month::June),
7 => Ok(Month::July),
8 => Ok(Month::August),
9 => Ok(Month::September),
10 => Ok(Month::October),
11 => Ok(Month::November),
12 => Ok(Month::December),
_ => Err(OutOfRange::new()),
}
}
}
Expand Down Expand Up @@ -318,24 +305,20 @@ mod month_serde {

#[cfg(test)]
mod tests {
use core::convert::TryFrom;

use super::Month;
use crate::{Datelike, TimeZone, Utc};
use crate::{Datelike, OutOfRange, TimeZone, Utc};

#[test]
fn test_month_enum_primitive_parse() {
use num_traits::FromPrimitive;

let jan_opt = Month::from_u32(1);
let feb_opt = Month::from_u64(2);
let dec_opt = Month::from_i64(12);
let no_month = Month::from_u32(13);
assert_eq!(jan_opt, Some(Month::January));
assert_eq!(feb_opt, Some(Month::February));
assert_eq!(dec_opt, Some(Month::December));
assert_eq!(no_month, None);
fn test_month_enum_try_from() {
assert_eq!(Month::try_from(1), Ok(Month::January));
assert_eq!(Month::try_from(2), Ok(Month::February));
assert_eq!(Month::try_from(12), Ok(Month::December));
assert_eq!(Month::try_from(13), Err(OutOfRange::new()));

let date = Utc.ymd(2019, 10, 28).and_hms(9, 10, 11);
assert_eq!(Month::from_u32(date.month()), Some(Month::October));
assert_eq!(Month::try_from(date.month() as u8), Ok(Month::October));

let month = Month::January;
let dt = Utc.ymd(2019, month.number_from_month(), 28).and_hms(9, 10, 11);
Expand Down
6 changes: 3 additions & 3 deletions src/naive/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
#[cfg(any(feature = "alloc", feature = "std", test))]
use core::borrow::Borrow;
use core::convert::TryFrom;
use core::ops::{Add, AddAssign, RangeInclusive, Sub, SubAssign};
use core::{fmt, str};

use num_integer::div_mod_floor;
use num_traits::ToPrimitive;
#[cfg(feature = "rkyv")]
use rkyv::{Archive, Deserialize, Serialize};

Expand Down Expand Up @@ -1059,7 +1059,7 @@ impl NaiveDate {
let year = self.year();
let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400);
let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal());
let cycle = (cycle as i32).checked_add(rhs.num_days().to_i32()?)?;
let cycle = (cycle as i32).checked_add(i32::try_from(rhs.num_days()).ok()?)?;
let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097);
year_div_400 += cycle_div_400y;

Expand Down Expand Up @@ -1090,7 +1090,7 @@ impl NaiveDate {
let year = self.year();
let (mut year_div_400, year_mod_400) = div_mod_floor(year, 400);
let cycle = internals::yo_to_cycle(year_mod_400 as u32, self.of().ordinal());
let cycle = (cycle as i32).checked_sub(rhs.num_days().to_i32()?)?;
let cycle = (cycle as i32).checked_sub(i32::try_from(rhs.num_days()).ok()?)?;
let (cycle_div_400y, cycle) = div_mod_floor(cycle, 146_097);
year_div_400 += cycle_div_400y;

Expand Down
6 changes: 3 additions & 3 deletions src/naive/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
#[cfg(any(feature = "alloc", feature = "std", test))]
use core::borrow::Borrow;
use core::convert::TryFrom;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::{fmt, str};

use num_integer::div_mod_floor;
use num_traits::ToPrimitive;
#[cfg(feature = "rkyv")]
use rkyv::{Archive, Deserialize, Serialize};

Expand Down Expand Up @@ -157,8 +157,8 @@ impl NaiveDateTime {
#[inline]
pub fn from_timestamp_opt(secs: i64, nsecs: u32) -> Option<NaiveDateTime> {
let (days, secs) = div_mod_floor(secs, 86_400);
let date = days
.to_i32()
let date = i32::try_from(days)
.ok()
.and_then(|days| days.checked_add(719_163))
.and_then(NaiveDate::from_num_days_from_ce_opt);
let time = NaiveTime::from_num_seconds_from_midnight_opt(secs as u32, nsecs);
Expand Down
Loading

0 comments on commit 77f5eed

Please sign in to comment.