Skip to main content

things3_cloud/wire/
recurrence.rs

1use num_enum::{FromPrimitive, IntoPrimitive};
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use std::collections::BTreeMap;
5use strum::{Display, EnumString};
6
7/// Recurrence rule payload (`rr`) for recurring templates.
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
9pub struct RecurrenceRule {
10    /// `tp`: recurrence mode.
11    #[serde(rename = "tp", default)]
12    pub repeat_type: RecurrenceType,
13
14    /// `fu`: frequency unit bitmask.
15    #[serde(rename = "fu", default = "default_frequency_unit")]
16    pub frequency_unit: FrequencyUnit,
17
18    /// `fa`: frequency amount (every N units).
19    #[serde(rename = "fa", default = "default_frequency_amount")]
20    pub frequency_amount: i32,
21
22    /// `of`: offsets (weekday/day/ordinal selectors).
23    #[serde(rename = "of", default)]
24    pub offsets: Vec<BTreeMap<String, Value>>,
25
26    /// `sr`: recurrence start reference day timestamp.
27    #[serde(rename = "sr", default)]
28    pub start_reference: Option<i64>,
29
30    /// `ia`: initial anchor day timestamp for recurrence calculations.
31    #[serde(rename = "ia", default)]
32    pub initial_anchor: Option<i64>,
33
34    /// `ed`: recurrence end day timestamp (`64092211200` ~= effectively never).
35    #[serde(rename = "ed", default = "default_recurrence_end_date")]
36    pub end_date: i64,
37
38    /// `rc`: repeat count.
39    #[serde(rename = "rc", default)]
40    pub repeat_count: i32,
41
42    /// `ts`: task skip behavior metadata.
43    #[serde(rename = "ts", default)]
44    pub task_skip: i32,
45
46    /// `rrv`: recurrence rule version.
47    #[serde(rename = "rrv", default = "default_recurrence_rule_version")]
48    pub recurrence_rule_version: i32,
49}
50
51/// Recurrence mode (`rr.tp`).
52#[derive(
53    Debug,
54    Clone,
55    Copy,
56    Serialize,
57    Deserialize,
58    PartialEq,
59    Eq,
60    Display,
61    EnumString,
62    FromPrimitive,
63    IntoPrimitive,
64)]
65#[repr(i32)]
66#[serde(from = "i32", into = "i32")]
67pub enum RecurrenceType {
68    /// Fixed schedule cadence.
69    FixedSchedule = 0,
70    /// Interval anchored after completion date.
71    AfterCompletion = 1,
72
73    /// Unknown value preserved for forward compatibility.
74    #[num_enum(catch_all)]
75    #[strum(disabled, to_string = "{0}")]
76    Unknown(i32),
77}
78
79#[expect(
80    clippy::derivable_impls,
81    reason = "num_enum(catch_all) conflicts with #[default]"
82)]
83impl Default for RecurrenceType {
84    fn default() -> Self {
85        Self::FixedSchedule
86    }
87}
88
89/// Recurrence frequency unit (`rr.fu`).
90#[derive(
91    Debug,
92    Clone,
93    Copy,
94    Serialize,
95    Deserialize,
96    PartialEq,
97    Eq,
98    Display,
99    EnumString,
100    FromPrimitive,
101    IntoPrimitive,
102)]
103#[repr(i32)]
104#[serde(from = "i32", into = "i32")]
105pub enum FrequencyUnit {
106    /// Daily bitmask value `8`.
107    Daily = 8,
108    /// Monthly bitmask value `16`.
109    Monthly = 16,
110    /// Weekly bitmask value `256`.
111    Weekly = 256,
112
113    /// Unknown value preserved for forward compatibility.
114    #[num_enum(catch_all)]
115    #[strum(disabled, to_string = "{0}")]
116    Unknown(i32),
117}
118
119#[expect(
120    clippy::derivable_impls,
121    reason = "num_enum(catch_all) conflicts with #[default]"
122)]
123impl Default for FrequencyUnit {
124    fn default() -> Self {
125        Self::Weekly
126    }
127}
128
129/// Default recurrence frequency unit (`rr.fu`) is weekly.
130fn default_frequency_unit() -> FrequencyUnit {
131    FrequencyUnit::Weekly
132}
133
134/// Default recurrence frequency amount (`rr.fa`) is every 1 unit.
135const fn default_frequency_amount() -> i32 {
136    1
137}
138
139/// Default recurrence end date (`rr.ed`) far in the future (~year 4001).
140const fn default_recurrence_end_date() -> i64 {
141    64_092_211_200
142}
143
144/// Current observed recurrence rule version (`rrv`).
145const fn default_recurrence_rule_version() -> i32 {
146    4
147}