diff --git a/ruma-common/src/push.rs b/ruma-common/src/push.rs index 9934b092..c32e9228 100644 --- a/ruma-common/src/push.rs +++ b/ruma-common/src/push.rs @@ -30,7 +30,7 @@ pub use self::{ condition::{ ComparisonOperator, FlattenedJson, PushCondition, PushConditionRoomCtx, RoomMemberCountIs, }, - iter::{AnyPushRule, RulesetIntoIter}, + iter::{AnyPushRule, RulesetIntoIter, RulesetIter}, }; /// A push ruleset scopes a set of rules according to some criteria. @@ -67,6 +67,13 @@ impl Ruleset { Default::default() } + /// Creates a borrowing iterator over all push rules in this `Ruleset`. + /// + /// For an owning iterator, use `.into_iter()`. + pub fn iter(&self) -> RulesetIter { + self.into_iter() + } + /// Adds a rule to the rule set. /// /// Returns `true` if the new rule was correctly added, and `false` diff --git a/ruma-common/src/push/iter.rs b/ruma-common/src/push/iter.rs index b261c021..aa817e9b 100644 --- a/ruma-common/src/push/iter.rs +++ b/ruma-common/src/push/iter.rs @@ -1,4 +1,4 @@ -use indexmap::set::IntoIter as IndexSetIntoIter; +use indexmap::set::{IntoIter as IndexSetIntoIter, Iter as IndexSetIter}; use super::{ConditionalPushRule, PatternedPushRule, Ruleset, SimplePushRule}; @@ -83,3 +83,74 @@ impl IntoIterator for Ruleset { } } } + +/// Reference to any kind of push rule. +#[derive(Clone, Copy, Debug)] +pub enum AnyPushRuleRef<'a> { + /// Rules that override all other kinds. + Override(&'a ConditionalPushRule), + + /// Content-specific rules. + Content(&'a PatternedPushRule), + + /// Room-specific rules. + Room(&'a SimplePushRule), + + /// Sender-specific rules. + Sender(&'a SimplePushRule), + + /// Lowest priority rules. + Underride(&'a ConditionalPushRule), +} + +impl<'a> AnyPushRuleRef<'a> { + /// Get the `rule_id` of the push rule. + pub fn rule_id(self) -> &'a str { + match self { + Self::Override(rule) => &rule.rule_id, + Self::Underride(rule) => &rule.rule_id, + Self::Content(rule) => &rule.rule_id, + Self::Room(rule) => &rule.rule_id, + Self::Sender(rule) => &rule.rule_id, + } + } +} + +/// Iterator type for `Ruleset` +#[derive(Debug)] +pub struct RulesetIter<'a> { + content: IndexSetIter<'a, PatternedPushRule>, + override_: IndexSetIter<'a, ConditionalPushRule>, + room: IndexSetIter<'a, SimplePushRule>, + sender: IndexSetIter<'a, SimplePushRule>, + underride: IndexSetIter<'a, ConditionalPushRule>, +} + +impl<'a> Iterator for RulesetIter<'a> { + type Item = AnyPushRuleRef<'a>; + + fn next(&mut self) -> Option { + self.override_ + .next() + .map(AnyPushRuleRef::Override) + .or_else(|| self.content.next().map(AnyPushRuleRef::Content)) + .or_else(|| self.room.next().map(AnyPushRuleRef::Room)) + .or_else(|| self.sender.next().map(AnyPushRuleRef::Sender)) + .or_else(|| self.underride.next().map(AnyPushRuleRef::Underride)) + } +} + +impl<'a> IntoIterator for &'a Ruleset { + type Item = AnyPushRuleRef<'a>; + type IntoIter = RulesetIter<'a>; + + fn into_iter(self) -> Self::IntoIter { + RulesetIter { + content: self.content.iter(), + override_: self.override_.iter(), + room: self.room.iter(), + sender: self.sender.iter(), + underride: self.underride.iter(), + } + } +}