270 lines
9.9 KiB
Rust
270 lines
9.9 KiB
Rust
/*
|
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
|
*/
|
|
|
|
use super::ArchivedCalendarEventData;
|
|
use crate::calendar::CalendarEventData;
|
|
use ahash::AHashSet;
|
|
use calcard::common::timezone::Tz;
|
|
use chrono::{DateTime, TimeZone};
|
|
use store::write::bitpack::BitpackIterator;
|
|
use types::TimeRange;
|
|
use utils::codec::leb128::Leb128Reader;
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct CalendarEventExpansion {
|
|
pub comp_id: u32,
|
|
pub expansion_id: u32,
|
|
pub start: i64,
|
|
pub end: i64,
|
|
}
|
|
|
|
impl ArchivedCalendarEventData {
|
|
pub fn expand(&self, default_tz: Tz, limit: TimeRange) -> Option<Vec<CalendarEventExpansion>> {
|
|
let mut expansion = Vec::with_capacity(self.time_ranges.len());
|
|
let base_offset = self.base_offset.to_native();
|
|
let mut base_expansion_id = 0;
|
|
|
|
'outer: for range in self.time_ranges.iter() {
|
|
let instances = range.instances.as_ref();
|
|
let (offset_or_count, bytes_read) = instances.read_leb128::<u32>()?;
|
|
|
|
let comp_id = range.id.to_native() as u32;
|
|
let duration = range.duration.to_native() as i64;
|
|
let mut start_tz = Tz::from_id(range.start_tz.to_native())?;
|
|
let mut end_tz = Tz::from_id(range.end_tz.to_native())?;
|
|
let is_todo = self.event.components[comp_id as usize]
|
|
.component_type
|
|
.is_todo();
|
|
|
|
if start_tz.is_floating() && !default_tz.is_floating() {
|
|
start_tz = default_tz;
|
|
}
|
|
if end_tz.is_floating() && !default_tz.is_floating() {
|
|
end_tz = default_tz;
|
|
}
|
|
|
|
if instances.len() > bytes_read {
|
|
// Recurring event
|
|
let unpacker =
|
|
BitpackIterator::from_bytes_and_offset(instances, bytes_read, offset_or_count);
|
|
let mut expansion_id = base_expansion_id;
|
|
base_expansion_id += offset_or_count;
|
|
for start_offset in unpacker {
|
|
let start_date_naive = start_offset as i64 + base_offset;
|
|
let end_date_naive = start_date_naive + duration;
|
|
let (Some(start), Some(end)) = (
|
|
resolve_local(start_tz, start_date_naive),
|
|
resolve_local(end_tz, end_date_naive),
|
|
) else {
|
|
expansion_id += 1;
|
|
continue;
|
|
};
|
|
|
|
if limit.is_in_range(is_todo, start, end) {
|
|
expansion.push(CalendarEventExpansion {
|
|
comp_id,
|
|
expansion_id,
|
|
start,
|
|
end,
|
|
});
|
|
} else if start > limit.end {
|
|
continue 'outer;
|
|
}
|
|
|
|
expansion_id += 1;
|
|
}
|
|
} else {
|
|
// Single event
|
|
let start_date_naive = offset_or_count as i64 + base_offset;
|
|
let end_date_naive = start_date_naive + duration;
|
|
if let (Some(start), Some(end)) = (
|
|
resolve_local(start_tz, start_date_naive),
|
|
resolve_local(end_tz, end_date_naive),
|
|
) && limit.is_in_range(is_todo, start, end)
|
|
{
|
|
expansion.push(CalendarEventExpansion {
|
|
comp_id,
|
|
expansion_id: base_expansion_id,
|
|
start,
|
|
end,
|
|
});
|
|
}
|
|
|
|
base_expansion_id += 1;
|
|
}
|
|
}
|
|
|
|
Some(expansion)
|
|
}
|
|
}
|
|
|
|
impl CalendarEventData {
|
|
pub fn expand_from_ids(
|
|
&self,
|
|
expansion_ids: &mut AHashSet<u32>,
|
|
default_tz: Tz,
|
|
) -> Option<Vec<CalendarEventExpansion>> {
|
|
let mut expansion = Vec::with_capacity(expansion_ids.len());
|
|
let base_offset = self.base_offset;
|
|
let mut base_expansion_id = 0;
|
|
|
|
'outer: for range in self.time_ranges.iter() {
|
|
let instances = range.instances.as_ref();
|
|
let (offset_or_count, bytes_read) = instances.read_leb128::<u32>()?;
|
|
let mut start_tz = Tz::from_id(range.start_tz)?;
|
|
let mut end_tz = Tz::from_id(range.end_tz)?;
|
|
|
|
if start_tz.is_floating() && !default_tz.is_floating() {
|
|
start_tz = default_tz;
|
|
}
|
|
if end_tz.is_floating() && !default_tz.is_floating() {
|
|
end_tz = default_tz;
|
|
}
|
|
|
|
if instances.len() > bytes_read {
|
|
let match_range = base_expansion_id..base_expansion_id + offset_or_count;
|
|
let mut match_count = expansion_ids
|
|
.iter()
|
|
.filter(|id| match_range.contains(id))
|
|
.count();
|
|
let mut expansion_id = base_expansion_id;
|
|
base_expansion_id += offset_or_count;
|
|
|
|
if match_count > 0 {
|
|
let unpacker = BitpackIterator::from_bytes_and_offset(
|
|
instances,
|
|
bytes_read,
|
|
offset_or_count,
|
|
);
|
|
for start_offset in unpacker {
|
|
if expansion_ids.remove(&expansion_id) {
|
|
let start_date_naive = start_offset as i64 + base_offset;
|
|
let end_date_naive = start_date_naive + range.duration as i64;
|
|
if let (Some(start), Some(end)) = (
|
|
resolve_local(start_tz, start_date_naive),
|
|
resolve_local(end_tz, end_date_naive),
|
|
) {
|
|
expansion.push(CalendarEventExpansion {
|
|
comp_id: range.id as u32,
|
|
expansion_id,
|
|
start,
|
|
end,
|
|
});
|
|
}
|
|
|
|
match_count -= 1;
|
|
if match_count == 0 {
|
|
if expansion_ids.is_empty() {
|
|
break 'outer;
|
|
} else {
|
|
continue 'outer;
|
|
}
|
|
}
|
|
}
|
|
expansion_id += 1;
|
|
}
|
|
}
|
|
} else {
|
|
if expansion_ids.remove(&base_expansion_id) {
|
|
// Single event
|
|
let start_date_naive = offset_or_count as i64 + base_offset;
|
|
let end_date_naive = start_date_naive + range.duration as i64;
|
|
if let (Some(start), Some(end)) = (
|
|
resolve_local(start_tz, start_date_naive),
|
|
resolve_local(end_tz, end_date_naive),
|
|
) {
|
|
expansion.push(CalendarEventExpansion {
|
|
comp_id: range.id as u32,
|
|
expansion_id: base_expansion_id,
|
|
start,
|
|
end,
|
|
});
|
|
}
|
|
|
|
if expansion_ids.is_empty() {
|
|
break 'outer;
|
|
}
|
|
}
|
|
|
|
base_expansion_id += 1;
|
|
}
|
|
}
|
|
|
|
if !expansion_ids.is_empty() {
|
|
expansion.extend(
|
|
expansion_ids
|
|
.drain()
|
|
.map(|expansion_id| CalendarEventExpansion {
|
|
comp_id: u32::MAX,
|
|
expansion_id,
|
|
start: i64::MAX,
|
|
end: i64::MAX,
|
|
}),
|
|
);
|
|
}
|
|
|
|
Some(expansion)
|
|
}
|
|
|
|
pub fn expand_single(&self, comp_id: u32, default_tz: Tz) -> Option<CalendarEventExpansion> {
|
|
let range = self.time_ranges.iter().find(|r| r.id as u32 == comp_id)?;
|
|
let instances = range.instances.as_ref();
|
|
let (offset_or_count, bytes_read) = instances.read_leb128::<u32>()?;
|
|
let mut start_tz = Tz::from_id(range.start_tz)?;
|
|
let mut end_tz = Tz::from_id(range.end_tz)?;
|
|
|
|
if start_tz.is_floating() && !default_tz.is_floating() {
|
|
start_tz = default_tz;
|
|
}
|
|
if end_tz.is_floating() && !default_tz.is_floating() {
|
|
end_tz = default_tz;
|
|
}
|
|
let start_offset = if instances.len() > bytes_read {
|
|
// Recurring event
|
|
let mut unpacker =
|
|
BitpackIterator::from_bytes_and_offset(instances, bytes_read, offset_or_count);
|
|
unpacker.next()?
|
|
} else {
|
|
// Single event
|
|
offset_or_count
|
|
};
|
|
let start_date_naive = start_offset as i64 + self.base_offset;
|
|
let end_date_naive = start_date_naive + range.duration as i64;
|
|
let start = resolve_local(start_tz, start_date_naive)?;
|
|
let end = resolve_local(end_tz, end_date_naive)?;
|
|
|
|
Some(CalendarEventExpansion {
|
|
comp_id,
|
|
expansion_id: u32::MAX,
|
|
start,
|
|
end,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl Default for CalendarEventExpansion {
|
|
fn default() -> Self {
|
|
Self {
|
|
comp_id: u32::MAX,
|
|
expansion_id: u32::MAX,
|
|
start: i64::MAX,
|
|
end: i64::MAX,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CalendarEventExpansion {
|
|
pub fn is_valid(&self) -> bool {
|
|
self.comp_id != u32::MAX && self.start != i64::MAX && self.end != i64::MAX
|
|
}
|
|
}
|
|
|
|
pub(crate) fn resolve_local(tz: Tz, naive_secs: i64) -> Option<i64> {
|
|
tz.from_local_datetime(&DateTime::from_timestamp(naive_secs, 0)?.naive_local())
|
|
.earliest()
|
|
.map(|dt| dt.timestamp())
|
|
}
|