Skip to content

feat: Lazy calendar-view iterators (days() / weeks()) #5

@AriajSarkar

Description

@AriajSarkar

Add lazy day/week iterators to Calendar that yield pre-bucketed event views, making it easy to plug eventix into UI frameworks (Yew, Leptos, Dioxus, etc.) for calendar rendering.

Motivation

eventix already has lazy iteration at the recurrence level (Recurrence::occurrences(start).take(5)), but calendar-level queries like events_between() and events_on_date() return eager Vec<EventOccurrence>. Building a calendar UI currently requires:

  1. Picking an arbitrary end date
  2. Collecting all occurrences into a Vec
  3. Manually grouping by date

There's no way to lazily walk forward through days/weeks and get events pre-grouped per time slice — which is exactly what UI rendering needs.

Proposed API

// Lazy day iteration — only computes events for days you consume
for day in cal.days(start).take(30) {
    println!("{}: {} events", day.date(), day.event_count());
    for event in day.events() {
        println!("  {} at {}", event.title(), event.occurrence_time);
    }
}

// Lazy week iteration — each WeekView contains 7 DayViews
for week in cal.weeks(start).take(4) {
    println!("Week of {}: {} events", week.start_date(), week.event_count());
}

// Backward iteration for scrolling into the past
let previous_30_days = cal.days_back(today).take(30);

New types

Type Purpose
DayView A single calendar day with its events pre-bucketed and sorted
WeekView 7 DayViews (Monday–Sunday)
OwnedEventOccurrence Owned event snapshot (no lifetime ties to Calendar)
DayIterator Lazy iterator yielding DayViews
WeekIterator Lazy iterator yielding WeekViews

Use Cases

  • Calendar UIs: Each DayView maps directly to a day cell/card component
  • Agenda views: .days(today).take(7).filter(|d| !d.is_empty())
  • Infinite scroll: Keep calling .next() as the user scrolls — no end date needed
  • Week/month grids: .weeks(start).take(4) for a month view

Design Decisions

  • Owned data: DayView owns its event data (OwnedEventOccurrence) instead of borrowing from Calendar, so views can be freely moved into UI component props
  • Infinite iterator: DayIterator never returns None — callers use .take(N) to bound it (matches OccurrenceIterator pattern)
  • Timezone-aware: Day boundaries respect the timezone passed to days(start), including DST transitions
  • Additive only: No breaking changes to existing APIs

Target

v0.5.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions