pub struct RecurrenceRule {
pub kind: RuleKind,
pub interval: Option<u32>,
pub anchor: Option<String>,
pub timezone: Option<Timezone>,
pub expression: Option<String>,
pub unit: Option<IntervalUnit>,
pub extensions: BTreeMap<String, Value>,
}Expand description
A supported schedule definition (data-model.md §2).
Field literals are public so a surface can build a rule directly; the
with_* builders exist for the common “start from a kind and add fields”
case. Nothing here is executable: expression is text a CronParser
interprets, and extensions is inert metadata.
§Unknown metadata (T005)
A key this build does not interpret lands in RecurrenceRule::extensions
and is written back on the next serialization. A newer tix that adds a
cadence field writes it into the same record, and this build preserves it
rather than silently dropping it on the next edit.
§Why PartialEq and not Eq
extensions holds serde_yaml::Value, which carries floats and therefore
has no Eq. Whole-struct equality is the priority; the missing Eq is the
documented consequence.
Fields§
§kind: RuleKindThe supported family this rule names.
interval: Option<u32>The cadence, where the family uses one.
anchor: Option<String>The stable schedule origin, as a canonical YYYY-MM-DD date.
Required for every family: an origin is what makes a schedule deterministic, and inventing one from the inject context would be exactly the silent guess C-009 escalates.
timezone: Option<Timezone>The explicit timezone policy, or None for a timezone-independent
calendar rule.
expression: Option<String>The cron-like expression; only meaningful for RuleKind::CronLike.
unit: Option<IntervalUnit>The RuleKind::Interval unit.
extensions: BTreeMap<String, Value>Metadata this build does not interpret, preserved verbatim.
Implementations§
Source§impl RecurrenceRule
impl RecurrenceRule
Sourcepub fn new(kind: RuleKind) -> Self
pub fn new(kind: RuleKind) -> Self
A bare rule of kind, with no cadence fields and no extensions.
Sourcepub fn with_interval(self, interval: u32) -> Self
pub fn with_interval(self, interval: u32) -> Self
Set the cadence.
Sourcepub fn with_anchor(self, anchor: impl Into<String>) -> Self
pub fn with_anchor(self, anchor: impl Into<String>) -> Self
Set the anchor, as a YYYY-MM-DD string.
Sourcepub fn with_timezone(self, timezone: Timezone) -> Self
pub fn with_timezone(self, timezone: Timezone) -> Self
Set the timezone policy.
Sourcepub fn with_expression(self, expression: impl Into<String>) -> Self
pub fn with_expression(self, expression: impl Into<String>) -> Self
Set the cron-like expression.
Sourcepub fn with_unit(self, unit: IntervalUnit) -> Self
pub fn with_unit(self, unit: IntervalUnit) -> Self
Set the interval unit.
Source§impl RecurrenceRule
impl RecurrenceRule
Sourcepub fn validate(&self) -> Result<(), RuleError>
pub fn validate(&self) -> Result<(), RuleError>
Validate the rule before it is persisted (T002, C-004).
Collects every finding rather than failing on the first, so a user fixes one rule once instead of discovering one problem per attempt. A refusal writes nothing, so an invalid rule can never reach a series file.
Sourcepub fn diagnostics(&self) -> Vec<RuleDiagnostic>
pub fn diagnostics(&self) -> Vec<RuleDiagnostic>
Every diagnostic, in deterministic field order.
Sourcepub fn anchor_date(&self) -> Result<Date, RuleError>
pub fn anchor_date(&self) -> Result<Date, RuleError>
The anchor as a calendar date, if the rule has a valid one.
Sourcepub fn anchor_key(&self) -> Result<DateKey, RuleError>
pub fn anchor_key(&self) -> Result<DateKey, RuleError>
The canonical anchor date key.
Source§impl RecurrenceRule
impl RecurrenceRule
Sourcepub fn next_occurrence(
&self,
context: &RuleContext,
) -> Result<DateKey, RuleError>
pub fn next_occurrence( &self, context: &RuleContext, ) -> Result<DateKey, RuleError>
The first occurrence strictly after context.today (T003).
The schedule is anchor, anchor + step, anchor + 2·step, …; the
result is the first of those dates after the injected date key. An anchor
in the future is therefore the answer, and an occurrence exactly on the
injected date is not the answer — “next” means next.
§Month-end and leap-day arithmetic, defined not guessed
A monthly step keeps the anchor’s day-of-month and re-anchors on the
target month’s last day when that day does not exist. An anchor of
2026-01-31 therefore recurs on 2026-02-28, and a 2024-02-29 anchor
recurs on 2025-02-28; the rules are here, in one place, rather than
left to whichever arithmetic a caller happened to write. A stored anchor
that is not a real date at all (2025-02-29) never reaches this function:
validation refuses it first.
§Ambiguity is refused
The rule is validated, then the injected context: a named zone on either side, an unparseable offset, or a rule/context offset disagreement is a diagnostic rather than a silent normalization. A computed occurrence outside the supported calendar range is a diagnostic too.
Trait Implementations§
Source§impl Clone for RecurrenceRule
impl Clone for RecurrenceRule
Source§impl Debug for RecurrenceRule
impl Debug for RecurrenceRule
Source§impl<'de> Deserialize<'de> for RecurrenceRule
impl<'de> Deserialize<'de> for RecurrenceRule
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl PartialEq for RecurrenceRule
impl PartialEq for RecurrenceRule
Source§impl Serialize for RecurrenceRule
impl Serialize for RecurrenceRule
impl StructuralPartialEq for RecurrenceRule
Auto Trait Implementations§
impl Freeze for RecurrenceRule
impl RefUnwindSafe for RecurrenceRule
impl Send for RecurrenceRule
impl Sync for RecurrenceRule
impl Unpin for RecurrenceRule
impl UnsafeUnpin for RecurrenceRule
impl UnwindSafe for RecurrenceRule
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more