recurdates 0.1.1

A library for calculating dates for recurring events.
Documentation
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate chrono;

use chrono::{DateTime, Local, Duration, TimeZone};
use chrono::naive::{MAX_DATE, MIN_DATE};

macro_rules! max_datetime {
    () => (Local.from_utc_datetime(&MAX_DATE.and_hms(23, 11, 59)))
}

macro_rules! min_datetime {
    () => (Local.from_utc_datetime(&MIN_DATE.and_hms(0, 0, 0)))
}

#[cfg(test)]
mod tests;
mod duration_format;

/// `ReDateTime` struct represents recurring datetime object
/// starting at `at` and repeating every `repeat` up to `until`.
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ReDateTime {
    pub at: DateTime<Local>,
    #[serde(with = "duration_format")]
    pub repeat: Duration,
    pub until: DateTime<Local>,
}

#[derive(Debug)]
pub struct ReDateTimeIter<'a> {
    from: &'a ReDateTime,
    adder: Option<Duration>,
}

impl ReDateTime {
    /// `ReDateTime` with no repeat.
    pub fn at(dt: DateTime<Local>) -> Self {
        ReDateTime { at: dt, repeat: Duration::zero(), until: max_datetime!() }
    }

    /// `ReDateTime` with infinite repeat.
    pub fn repeat(dt: DateTime<Local>, dur: Duration) -> Self {
        let lim = if dur < Duration::zero() { max_datetime!() } else { min_datetime!() };
        ReDateTime { at: dt, repeat: dur, until: lim - dur }
    }

    /// `ReDateTime` with a finite number of repeats.
    pub fn repeat_until(dt: DateTime<Local>, dur: Duration, til: DateTime<Local>) -> Self {
        ReDateTime { at: dt, repeat: dur, until: til - dur }
    }

    /// An iterator visiting datetimes in order. If `repeat` is negative, the iterator runs in reverse-chronological order.
    pub fn iter(&self) -> ReDateTimeIter {
        let adr = if self.repeat.is_zero() { None } else { Some(Duration::zero()) };
        ReDateTimeIter { from: &self, adder: adr }
    }
}

impl<'a> Iterator for ReDateTimeIter<'a> {
    type Item = DateTime<Local>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.adder.is_none() {
            return None;
        }

        let x = self.adder.unwrap();
        self.adder = self.adder.unwrap().checked_add(&self.from.repeat);

        let n = self.from.at + x;
        if self.from.repeat < Duration::zero() {
            if n >= self.from.until {
                return Some(n);
            }
        } else if n <= self.from.until {
            return Some(n);
        }
        None
    }
}