Skip to content

Commit

Permalink
Add Ord and PartialOrd to icu_calendar types (#3468)
Browse files Browse the repository at this point in the history
  • Loading branch information
sffc authored Jun 1, 2023
1 parent 6477748 commit 85ff0ae
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 12 deletions.
2 changes: 1 addition & 1 deletion components/calendar/src/any_calendar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ pub enum AnyCalendar {
}

/// The inner date type for [`AnyCalendar`]
#[derive(Clone, PartialEq, Eq, Debug)]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[non_exhaustive]
pub enum AnyDateInner {
/// A date for a [`Gregorian`] calendar
Expand Down
37 changes: 36 additions & 1 deletion components/calendar/src/calendar_arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use core::convert::TryInto;
use core::marker::PhantomData;
use tinystr::tinystr;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
#[allow(clippy::exhaustive_structs)] // this type is stable
pub struct ArithmeticDate<C: CalendarArithmetic> {
pub year: i32,
Expand Down Expand Up @@ -250,3 +250,38 @@ pub fn ordinal_solar_month_from_code(code: types::MonthCode) -> Option<u8> {
}
None
}

#[cfg(test)]
mod tests {
use super::*;
use crate::Iso;

#[test]
fn test_ord() {
let dates_in_order = [
ArithmeticDate::<Iso>::new(-10, 1, 1),
ArithmeticDate::<Iso>::new(-10, 1, 2),
ArithmeticDate::<Iso>::new(-10, 2, 1),
ArithmeticDate::<Iso>::new(-1, 1, 1),
ArithmeticDate::<Iso>::new(-1, 1, 2),
ArithmeticDate::<Iso>::new(-1, 2, 1),
ArithmeticDate::<Iso>::new(0, 1, 1),
ArithmeticDate::<Iso>::new(0, 1, 2),
ArithmeticDate::<Iso>::new(0, 2, 1),
ArithmeticDate::<Iso>::new(1, 1, 1),
ArithmeticDate::<Iso>::new(1, 1, 2),
ArithmeticDate::<Iso>::new(1, 2, 1),
ArithmeticDate::<Iso>::new(10, 1, 1),
ArithmeticDate::<Iso>::new(10, 1, 2),
ArithmeticDate::<Iso>::new(10, 2, 1),
];
for (i, i_date) in dates_in_order.iter().enumerate() {
for (j, j_date) in dates_in_order.iter().enumerate() {
let result1 = i_date.cmp(j_date);
let result2 = j_date.cmp(i_date);
assert_eq!(result1.reverse(), result2);
assert_eq!(i.cmp(&j), i_date.cmp(j_date));
}
}
}
}
4 changes: 2 additions & 2 deletions components/calendar/src/coptic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ use tinystr::tinystr;
///
/// This calendar supports two era codes: `"bd"`, and `"ad"`, corresponding to the Before Diocletian and After Diocletian/Anno Martyrum
/// eras. 1 A.M. is equivalent to 284 C.E.
#[derive(Copy, Clone, Debug, Hash, Default, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Hash, Default, Eq, PartialEq, PartialOrd, Ord)]
#[allow(clippy::exhaustive_structs)] // this type is stable
pub struct Coptic;

/// The inner date type used for representing [`Date`]s of [`Coptic`]. See [`Date`] and [`Coptic`] for more details.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub struct CopticDateInner(pub(crate) ArithmeticDate<Coptic>);

impl CalendarArithmetic for Coptic {
Expand Down
57 changes: 57 additions & 0 deletions components/calendar/src/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,29 @@ where

impl<A: AsCalendar> Eq for Date<A> {}

impl<C, A, B> PartialOrd<Date<B>> for Date<A>
where
C: Calendar,
C::DateInner: PartialOrd,
A: AsCalendar<Calendar = C>,
B: AsCalendar<Calendar = C>,
{
fn partial_cmp(&self, other: &Date<B>) -> Option<core::cmp::Ordering> {
self.inner.partial_cmp(&other.inner)
}
}

impl<C, A> Ord for Date<A>
where
C: Calendar,
C::DateInner: Ord,
A: AsCalendar<Calendar = C>,
{
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.inner.cmp(&other.inner)
}
}

impl<A: AsCalendar> fmt::Debug for Date<A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(
Expand All @@ -381,3 +404,37 @@ where
<<A as AsCalendar>::Calendar as Calendar>::DateInner: Copy,
{
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_ord() {
let dates_in_order = [
Date::try_new_iso_date(-10, 1, 1).unwrap(),
Date::try_new_iso_date(-10, 1, 2).unwrap(),
Date::try_new_iso_date(-10, 2, 1).unwrap(),
Date::try_new_iso_date(-1, 1, 1).unwrap(),
Date::try_new_iso_date(-1, 1, 2).unwrap(),
Date::try_new_iso_date(-1, 2, 1).unwrap(),
Date::try_new_iso_date(0, 1, 1).unwrap(),
Date::try_new_iso_date(0, 1, 2).unwrap(),
Date::try_new_iso_date(0, 2, 1).unwrap(),
Date::try_new_iso_date(1, 1, 1).unwrap(),
Date::try_new_iso_date(1, 1, 2).unwrap(),
Date::try_new_iso_date(1, 2, 1).unwrap(),
Date::try_new_iso_date(10, 1, 1).unwrap(),
Date::try_new_iso_date(10, 1, 2).unwrap(),
Date::try_new_iso_date(10, 2, 1).unwrap(),
];
for (i, i_date) in dates_in_order.iter().enumerate() {
for (j, j_date) in dates_in_order.iter().enumerate() {
let result1 = i_date.cmp(j_date);
let result2 = j_date.cmp(i_date);
assert_eq!(result1.reverse(), result2);
assert_eq!(i.cmp(&j), i_date.cmp(j_date));
}
}
}
}
52 changes: 52 additions & 0 deletions components/calendar/src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,32 @@ where
// We can do this since DateInner is required to be Eq by the Calendar trait
impl<A: AsCalendar> Eq for DateTime<A> {}

impl<C, A, B> PartialOrd<DateTime<B>> for DateTime<A>
where
C: Calendar,
C::DateInner: PartialOrd,
A: AsCalendar<Calendar = C>,
B: AsCalendar<Calendar = C>,
{
fn partial_cmp(&self, other: &DateTime<B>) -> Option<core::cmp::Ordering> {
match self.date.partial_cmp(&other.date) {
Some(core::cmp::Ordering::Equal) => self.time.partial_cmp(&other.time),
other => other,
}
}
}

impl<C, A> Ord for DateTime<A>
where
C: Calendar,
C::DateInner: Ord,
A: AsCalendar<Calendar = C>,
{
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
(&self.date, &self.time).cmp(&(&other.date, &other.time))
}
}

impl<A: AsCalendar + Clone> Clone for DateTime<A> {
fn clone(&self) -> Self {
Self {
Expand All @@ -152,3 +178,29 @@ where
<<A as AsCalendar>::Calendar as Calendar>::DateInner: Copy,
{
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_ord() {
let dates_in_order = [
DateTime::try_new_iso_datetime(0, 1, 1, 0, 0, 0).unwrap(),
DateTime::try_new_iso_datetime(0, 1, 1, 0, 0, 1).unwrap(),
DateTime::try_new_iso_datetime(0, 1, 1, 0, 1, 0).unwrap(),
DateTime::try_new_iso_datetime(0, 1, 1, 1, 0, 0).unwrap(),
DateTime::try_new_iso_datetime(0, 1, 2, 0, 0, 0).unwrap(),
DateTime::try_new_iso_datetime(0, 2, 1, 0, 0, 0).unwrap(),
DateTime::try_new_iso_datetime(1, 1, 1, 0, 0, 0).unwrap(),
];
for (i, i_date) in dates_in_order.iter().enumerate() {
for (j, j_date) in dates_in_order.iter().enumerate() {
let result1 = i_date.cmp(j_date);
let result2 = j_date.cmp(i_date);
assert_eq!(result1.reverse(), result2);
assert_eq!(i.cmp(&j), i_date.cmp(j_date));
}
}
}
}
4 changes: 2 additions & 2 deletions components/calendar/src/ethiopian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ pub enum EthiopianEraStyle {
/// the `"incar"` and `"pre-incar"` eras, 1 Incarnation is 9 CE. In the Amete Alem scheme, it instead has a single era,
/// `"mundi`, where 1 Anno Mundi is 5493 BCE. Dates before that use negative year numbers.
// The bool specifies whether dates should be in the Amete Alem era scheme
#[derive(Copy, Clone, Debug, Hash, Default, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Hash, Default, Eq, PartialEq, PartialOrd, Ord)]
pub struct Ethiopian(pub(crate) bool);

/// The inner date type used for representing [`Date`]s of [`Ethiopian`]. See [`Date`] and [`Ethiopian`] for more details.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub struct EthiopianDateInner(ArithmeticDate<Ethiopian>);

impl CalendarArithmetic for Ethiopian {
Expand Down
2 changes: 1 addition & 1 deletion components/calendar/src/gregorian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use tinystr::tinystr;
#[allow(clippy::exhaustive_structs)] // this type is stable
pub struct Gregorian;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
/// The inner date type used for representing [`Date`]s of [`Gregorian`]. See [`Date`] and [`Gregorian`] for more details.
pub struct GregorianDateInner(IsoDateInner);

Expand Down
4 changes: 2 additions & 2 deletions components/calendar/src/indian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ use tinystr::tinystr;
/// # Era codes
///
/// This calendar has a single era: `"saka"`, with Saka 0 being 78 CE. Dates before this era use negative years.
#[derive(Copy, Clone, Debug, Hash, Default, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Hash, Default, Eq, PartialEq, PartialOrd, Ord)]
#[allow(clippy::exhaustive_structs)] // this type is stable
pub struct Indian;

/// The inner date type used for representing [`Date`]s of [`Indian`]. See [`Date`] and [`Indian`] for more details.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub struct IndianDateInner(ArithmeticDate<Indian>);

impl CalendarArithmetic for Indian {
Expand Down
4 changes: 2 additions & 2 deletions components/calendar/src/iso.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ const EPOCH: i32 = 1;
///
/// This calendar supports one era, `"default"`

#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[allow(clippy::exhaustive_structs)] // this type is stable
pub struct Iso;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
/// The inner date type used for representing [`Date`]s of [`Iso`]. See [`Date`] and [`Iso`] for more details.
pub struct IsoDateInner(pub(crate) ArithmeticDate<Iso>);

Expand Down
2 changes: 1 addition & 1 deletion components/calendar/src/japanese.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub struct Japanese {
#[derive(Clone, Debug, Default)]
pub struct JapaneseExtended(Japanese);

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
/// The inner date type used for representing [`Date`]s of [`Japanese`]. See [`Date`] and [`Japanese`] for more details.
pub struct JapaneseDateInner {
inner: IsoDateInner,
Expand Down

0 comments on commit 85ff0ae

Please sign in to comment.