io-calendar 0.0.1

Set of I/O-free coroutines to manage calendars
use std::{collections::HashSet, path::Path};

use io_fs::io::FsIo;
use io_vdir::{
    coroutines::list_items::{
        ListItems as ListVdirItems, ListItemsError as ListVdirItemsError,
        ListItemsResult as ListVdirItemsResult,
    },
    item::ItemKind,
};
use thiserror::Error;

use crate::item::CalendarItem;

#[derive(Clone, Debug, Error)]
pub enum ListCalendarItemsError {
    #[error("List calendar items error")]
    ListVdirItems(#[from] ListVdirItemsError),
}

#[derive(Clone, Debug)]
pub enum ListCalendarItemsResult {
    Ok(HashSet<CalendarItem>),
    Err(ListCalendarItemsError),
    Io(FsIo),
}

#[derive(Debug)]
pub struct ListCalendarItems(ListVdirItems);

impl ListCalendarItems {
    pub fn new(root: impl AsRef<Path>, calendar_id: impl AsRef<str>) -> Self {
        Self(ListVdirItems::new(root.as_ref().join(calendar_id.as_ref())))
    }

    pub fn resume(&mut self, input: Option<FsIo>) -> ListCalendarItemsResult {
        let all_items = loop {
            match self.0.resume(input) {
                ListVdirItemsResult::Ok(items) => break items,
                ListVdirItemsResult::Err(err) => return ListCalendarItemsResult::Err(err.into()),
                ListVdirItemsResult::Io(io) => return ListCalendarItemsResult::Io(io),
            }
        };

        let mut items = HashSet::new();

        for item in all_items {
            let Some(parent) = item.path.parent() else {
                continue;
            };

            let Some(calendar_id) = parent.file_stem() else {
                continue;
            };

            let Some(id) = item.path.file_stem() else {
                continue;
            };

            let ItemKind::Ical(ical) = item.kind else {
                continue;
            };

            items.insert(CalendarItem {
                id: id.to_string_lossy().to_string(),
                calendar_id: calendar_id.to_string_lossy().to_string(),
                ical,
            });
        }

        ListCalendarItemsResult::Ok(items)
    }
}