use std::fmt::{self, Debug};
use std::result;
use once_cell::sync::Lazy;
use regex::Regex;
#[doc(inline)]
use crate::date::DateError;
use crate::error::Error;
use crate::Entry;
#[derive(Debug)]
enum Stage {
Before,
In,
After
}
pub struct TaskLineIter<'a, I>
where
I: Iterator<Item = String>
{
iter: I,
stage: Stage,
start: &'a str,
end: &'a str
}
impl<'a, I> Debug for TaskLineIter<'a, I>
where
I: Iterator<Item = String>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> result::Result<(), fmt::Error> {
f.debug_struct("TaskLineIter")
.field("iter", &"Iter")
.field("stage", &self.stage)
.field("start", &self.start)
.field("end", &self.end)
.finish()
}
}
static DATE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^\d{4}-\d\d-\d\d$").expect("Date regex invalid"));
impl<'a, I> TaskLineIter<'a, I>
where
I: Iterator<Item = String>
{
pub fn new(iter: I, start: &'a str, end: &'a str) -> crate::Result<Self> {
if !DATE.is_match(start) {
return Err(Error::StartDateFormat);
}
if !DATE.is_match(end) {
return Err(Error::EndDateFormat);
}
if start >= end {
return Err(DateError::WrongDateOrder.into());
}
Ok(Self { iter, stage: Stage::Before, start, end })
}
pub fn last_line_before(mut self) -> Option<String> {
let mut prev: Option<String> = None;
for line in self.iter.by_ref() {
if let Some(date) = Entry::date_from_line(&line) {
if self.start <= date && date < self.end {
return prev;
}
prev = Some(line);
}
}
None
}
fn find_first(&mut self) -> Option<String> {
for line in self.iter.by_ref() {
if let Some(date) = Entry::date_from_line(&line) {
if self.start <= date && date < self.end {
return Some(line);
}
}
}
None
}
fn get_next(&mut self) -> Option<String> {
if let Some(line) = self.iter.next() {
if let Some(date) = Entry::date_from_line(&line) {
if date < self.end {
return Some(line);
}
}
}
None
}
}
impl<'a, I> Iterator for TaskLineIter<'a, I>
where
I: Iterator<Item = String>
{
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
match self.stage {
Stage::Before => {
if let Some(line) = self.find_first() {
self.stage = Stage::In;
return Some(line);
}
}
Stage::In => {
if let Some(line) = self.get_next() {
return Some(line);
}
}
Stage::After => {}
}
self.stage = Stage::After;
None
}
}
#[cfg(test)]
mod tests {
use assert2::{assert, let_assert};
use super::*;
use crate::date::DateError;
#[test]
fn test_successful_new() {
let tasks: Vec<String> = Vec::new();
let mut e_iter = tasks.into_iter();
let_assert!(Ok(_) = TaskLineIter::new(&mut e_iter, "2021-06-17", "2021-06-18"));
}
#[test]
fn test_new_bad_start() {
let tasks: Vec<String> = Vec::new();
let mut e_iter = tasks.into_iter();
let_assert!(Err(err) = TaskLineIter::new(&mut e_iter, "foo", "2021-06-18"));
assert!(err == Error::StartDateFormat);
}
#[test]
fn test_new_bad_end() {
let tasks: Vec<String> = Vec::new();
let mut e_iter = tasks.into_iter();
let_assert!(Err(err) = TaskLineIter::new(&mut e_iter, "2021-06-17", "bar"));
assert!(err == Error::EndDateFormat);
}
#[test]
fn test_new_wrong_order() {
let tasks: Vec<String> = Vec::new();
let mut e_iter = tasks.into_iter();
let_assert!(Err(err) = TaskLineIter::new(&mut e_iter, "2021-06-17", "2021-06-14"));
assert!(err == Error::DateError { source: DateError::WrongDateOrder });
}
fn make_entity_lines() -> Vec<String> {
[
"2021-05-30 08:00:00 junk",
"2021-05-30 08:10:00 junk",
"2021-05-30 08:20:00 junk",
"2021-05-30 08:30:00 junk",
"2021-05-30 08:40:00 junk",
"2021-05-30 08:50:00 junk",
"2021-05-30 09:00:00 junk",
"2021-06-01 08:00:00 tuesday 1",
"2021-06-01 08:30:00 tuesday 2",
"2021-06-02 08:00:00 wednesday 1",
"2021-06-02 08:30:00 wednesday 2",
"2021-06-03 08:00:00 thursday 1",
"2021-06-03 08:30:00 thursday 2",
"2021-06-04 08:00:00 friday 1",
"2021-06-04 08:30:00 friday 2",
"2021-06-07 08:00:00 monday 1",
"2021-06-07 08:30:00 monday 2",
"2021-06-08 08:00:00 final"
]
.iter()
.map(|&s| String::from(s))
.collect()
}
#[test]
fn test_before_tasks() {
let tasks = make_entity_lines();
let mut e_iter = tasks.into_iter();
let_assert!(Ok(mut iter) = TaskLineIter::new(&mut e_iter, "2021-04-17", "2021-04-18"));
assert!(iter.next() == None);
}
#[test]
fn test_after_tasks() {
let tasks = make_entity_lines();
let mut e_iter = tasks.into_iter();
let_assert!(Ok(mut iter) = TaskLineIter::new(&mut e_iter, "2021-06-17", "2021-06-18"));
assert!(iter.next() == None);
}
#[test]
fn test_skip_beginning() {
let tasks = make_entity_lines();
let mut e_iter = tasks.into_iter();
let_assert!(Ok(mut iter) = TaskLineIter::new(&mut e_iter, "2021-06-01", "2021-06-02"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-01 08:00:00 tuesday 1"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-01 08:30:00 tuesday 2"));
assert!(iter.next() == None);
}
#[test]
fn test_multiple_days() {
let tasks = make_entity_lines();
let mut e_iter = tasks.into_iter();
let_assert!(Ok(mut iter) = TaskLineIter::new(&mut e_iter, "2021-06-01", "2021-06-04"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-01 08:00:00 tuesday 1"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-01 08:30:00 tuesday 2"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-02 08:00:00 wednesday 1"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-02 08:30:00 wednesday 2"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-03 08:00:00 thursday 1"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-03 08:30:00 thursday 2"));
assert!(iter.next() == None);
}
#[test]
fn test_start_in_gap() {
let tasks = make_entity_lines();
let mut e_iter = tasks.into_iter();
let_assert!(Ok(mut iter) = TaskLineIter::new(&mut e_iter, "2021-06-05", "2021-06-08"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-07 08:00:00 monday 1"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-07 08:30:00 monday 2"));
assert!(iter.next() == None);
}
#[test]
fn test_end_in_gap() {
let tasks = make_entity_lines();
let mut e_iter = tasks.into_iter();
let_assert!(Ok(mut iter) = TaskLineIter::new(&mut e_iter, "2021-06-04", "2021-06-06"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-04 08:00:00 friday 1"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-04 08:30:00 friday 2"));
assert!(iter.next() == None);
}
#[test]
fn test_missing_in_range() {
let tasks = make_entity_lines();
let mut e_iter = tasks.into_iter();
let_assert!(Ok(mut iter) = TaskLineIter::new(&mut e_iter, "2021-06-06", "2021-06-07"));
assert!(iter.next() == None);
}
#[test]
fn test_to_end() {
let tasks = make_entity_lines();
let mut e_iter = tasks.into_iter();
let_assert!(Ok(mut iter) = TaskLineIter::new(&mut e_iter, "2021-06-07", "2021-06-10"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-07 08:00:00 monday 1"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-07 08:30:00 monday 2"));
let_assert!(Some(line) = iter.next());
assert!(line == String::from("2021-06-08 08:00:00 final"));
assert!(iter.next() == None);
}
}