1use indexmap::set::{IntoIter as IndexSetIntoIter, Iter as IndexSetIter};
2
3use super::{
4 Action, ConditionalPushRule, FlattenedJson, PatternedPushRule, PushConditionRoomCtx, PushRule, Ruleset,
5 SimplePushRule, condition,
6};
7use crate::{OwnedRoomId, OwnedUserId};
8
9#[derive(Clone, Debug)]
11pub enum AnyPushRule {
12 Override(ConditionalPushRule),
14
15 Content(PatternedPushRule),
17
18 Room(SimplePushRule<OwnedRoomId>),
20
21 Sender(SimplePushRule<OwnedUserId>),
23
24 Underride(ConditionalPushRule),
26}
27
28impl AnyPushRule {
29 pub fn as_ref(&self) -> AnyPushRuleRef<'_> {
31 match self {
32 Self::Override(o) => AnyPushRuleRef::Override(o),
33 Self::Content(c) => AnyPushRuleRef::Content(c),
34 Self::Room(r) => AnyPushRuleRef::Room(r),
35 Self::Sender(s) => AnyPushRuleRef::Sender(s),
36 Self::Underride(u) => AnyPushRuleRef::Underride(u),
37 }
38 }
39
40 pub fn enabled(&self) -> bool {
42 self.as_ref().enabled()
43 }
44
45 pub fn actions(&self) -> &[Action] {
47 self.as_ref().actions()
48 }
49
50 pub fn triggers_highlight(&self) -> bool {
52 self.as_ref().triggers_highlight()
53 }
54
55 pub fn triggers_notification(&self) -> bool {
57 self.as_ref().triggers_notification()
58 }
59
60 pub fn triggers_sound(&self) -> Option<&str> {
62 self.as_ref().triggers_sound()
63 }
64
65 pub fn rule_id(&self) -> &str {
67 self.as_ref().rule_id()
68 }
69
70 pub fn is_server_default(&self) -> bool {
72 self.as_ref().is_server_default()
73 }
74
75 pub fn applies(&self, event: &FlattenedJson, context: &PushConditionRoomCtx) -> bool {
82 self.as_ref().applies(event, context)
83 }
84}
85
86impl From<AnyPushRule> for PushRule {
87 fn from(push_rule: AnyPushRule) -> Self {
88 #[allow(unreachable_patterns)]
89 match push_rule {
90 AnyPushRule::Override(r) => r.into(),
91 AnyPushRule::Content(r) => r.into(),
92 AnyPushRule::Room(r) => r.into(),
93 AnyPushRule::Sender(r) => r.into(),
94 AnyPushRule::Underride(r) => r.into(),
95 _ => unreachable!(),
96 }
97 }
98}
99
100impl<'a> From<AnyPushRuleRef<'a>> for PushRule {
101 fn from(push_rule: AnyPushRuleRef<'a>) -> Self {
102 push_rule.to_owned().into()
103 }
104}
105
106#[derive(Debug)]
108pub struct RulesetIntoIter {
109 content: IndexSetIntoIter<PatternedPushRule>,
110 override_: IndexSetIntoIter<ConditionalPushRule>,
111 room: IndexSetIntoIter<SimplePushRule<OwnedRoomId>>,
112 sender: IndexSetIntoIter<SimplePushRule<OwnedUserId>>,
113 underride: IndexSetIntoIter<ConditionalPushRule>,
114}
115
116impl Iterator for RulesetIntoIter {
117 type Item = AnyPushRule;
118
119 fn next(&mut self) -> Option<Self::Item> {
120 self.override_
121 .next()
122 .map(AnyPushRule::Override)
123 .or_else(|| self.content.next().map(AnyPushRule::Content))
124 .or_else(|| self.room.next().map(AnyPushRule::Room))
125 .or_else(|| self.sender.next().map(AnyPushRule::Sender))
126 .or_else(|| self.underride.next().map(AnyPushRule::Underride))
127 }
128}
129
130impl IntoIterator for Ruleset {
131 type Item = AnyPushRule;
132 type IntoIter = RulesetIntoIter;
133
134 fn into_iter(self) -> Self::IntoIter {
135 RulesetIntoIter {
136 content: self.content.into_iter(),
137 override_: self.override_.into_iter(),
138 room: self.room.into_iter(),
139 sender: self.sender.into_iter(),
140 underride: self.underride.into_iter(),
141 }
142 }
143}
144
145#[derive(Clone, Copy, Debug)]
147pub enum AnyPushRuleRef<'a> {
148 Override(&'a ConditionalPushRule),
150
151 Content(&'a PatternedPushRule),
153
154 Room(&'a SimplePushRule<OwnedRoomId>),
156
157 Sender(&'a SimplePushRule<OwnedUserId>),
159
160 Underride(&'a ConditionalPushRule),
162}
163
164impl<'a> AnyPushRuleRef<'a> {
165 pub fn to_owned(self) -> AnyPushRule {
167 match self {
168 Self::Override(o) => AnyPushRule::Override(o.clone()),
169 Self::Content(c) => AnyPushRule::Content(c.clone()),
170 Self::Room(r) => AnyPushRule::Room(r.clone()),
171 Self::Sender(s) => AnyPushRule::Sender(s.clone()),
172 Self::Underride(u) => AnyPushRule::Underride(u.clone()),
173 }
174 }
175
176 pub fn enabled(self) -> bool {
178 match self {
179 Self::Override(rule) => rule.enabled,
180 Self::Underride(rule) => rule.enabled,
181 Self::Content(rule) => rule.enabled,
182 Self::Room(rule) => rule.enabled,
183 Self::Sender(rule) => rule.enabled,
184 }
185 }
186
187 pub fn actions(self) -> &'a [Action] {
189 match self {
190 Self::Override(rule) => &rule.actions,
191 Self::Underride(rule) => &rule.actions,
192 Self::Content(rule) => &rule.actions,
193 Self::Room(rule) => &rule.actions,
194 Self::Sender(rule) => &rule.actions,
195 }
196 }
197
198 pub fn triggers_highlight(self) -> bool {
200 self.actions().iter().any(|a| a.is_highlight())
201 }
202
203 pub fn triggers_notification(self) -> bool {
205 self.actions().iter().any(|a| a.should_notify())
206 }
207
208 pub fn triggers_sound(self) -> Option<&'a str> {
210 self.actions().iter().find_map(|a| a.sound())
211 }
212
213 pub fn rule_id(self) -> &'a str {
215 match self {
216 Self::Override(rule) => &rule.rule_id,
217 Self::Underride(rule) => &rule.rule_id,
218 Self::Content(rule) => &rule.rule_id,
219 Self::Room(rule) => rule.rule_id.as_ref(),
220 Self::Sender(rule) => rule.rule_id.as_ref(),
221 }
222 }
223
224 pub fn is_server_default(self) -> bool {
226 match self {
227 Self::Override(rule) => rule.default,
228 Self::Underride(rule) => rule.default,
229 Self::Content(rule) => rule.default,
230 Self::Room(rule) => rule.default,
231 Self::Sender(rule) => rule.default,
232 }
233 }
234
235 pub fn applies(self, event: &FlattenedJson, context: &PushConditionRoomCtx) -> bool {
242 if event.get_str("sender").is_some_and(|sender| sender == context.user_id) {
243 return false;
244 }
245
246 match self {
247 Self::Override(rule) => rule.applies(event, context),
248 Self::Underride(rule) => rule.applies(event, context),
249 Self::Content(rule) => rule.applies_to("content.body", event, context),
250 Self::Room(rule) => {
251 rule.enabled && condition::check_event_match(event, "room_id", rule.rule_id.as_ref(), context)
252 }
253 Self::Sender(rule) => {
254 rule.enabled && condition::check_event_match(event, "sender", rule.rule_id.as_ref(), context)
255 }
256 }
257 }
258}
259
260#[derive(Debug)]
262pub struct RulesetIter<'a> {
263 content: IndexSetIter<'a, PatternedPushRule>,
264 override_: IndexSetIter<'a, ConditionalPushRule>,
265 room: IndexSetIter<'a, SimplePushRule<OwnedRoomId>>,
266 sender: IndexSetIter<'a, SimplePushRule<OwnedUserId>>,
267 underride: IndexSetIter<'a, ConditionalPushRule>,
268}
269
270impl<'a> Iterator for RulesetIter<'a> {
271 type Item = AnyPushRuleRef<'a>;
272
273 fn next(&mut self) -> Option<Self::Item> {
274 self.override_
275 .next()
276 .map(AnyPushRuleRef::Override)
277 .or_else(|| self.content.next().map(AnyPushRuleRef::Content))
278 .or_else(|| self.room.next().map(AnyPushRuleRef::Room))
279 .or_else(|| self.sender.next().map(AnyPushRuleRef::Sender))
280 .or_else(|| self.underride.next().map(AnyPushRuleRef::Underride))
281 }
282}
283
284impl<'a> IntoIterator for &'a Ruleset {
285 type Item = AnyPushRuleRef<'a>;
286 type IntoIter = RulesetIter<'a>;
287
288 fn into_iter(self) -> Self::IntoIter {
289 RulesetIter {
290 content: self.content.iter(),
291 override_: self.override_.iter(),
292 room: self.room.iter(),
293 sender: self.sender.iter(),
294 underride: self.underride.iter(),
295 }
296 }
297}