1pub mod create_filter;
4pub mod get_filter;
5
6mod lazy_load;
7mod url;
8
9use js_int::UInt;
10use ruma_common::{serde::StringEnum, OwnedRoomId, OwnedUserId};
11use serde::{Deserialize, Serialize};
12
13pub use self::{lazy_load::LazyLoadOptions, url::UrlFilter};
14use crate::PrivOwnedStr;
15
16#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/string_enum.md"))]
18#[derive(Clone, Default, PartialEq, Eq, StringEnum)]
19#[ruma_enum(rename_all = "snake_case")]
20#[non_exhaustive]
21pub enum EventFormat {
22 #[default]
24 Client,
25
26 Federation,
28
29 #[doc(hidden)]
30 _Custom(PrivOwnedStr),
31}
32
33#[derive(Clone, Debug, Default, Deserialize, Serialize)]
35#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
36pub struct RoomEventFilter {
37 #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
43 pub not_types: Vec<String>,
44
45 #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
50 pub not_rooms: Vec<OwnedRoomId>,
51
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub limit: Option<UInt>,
55
56 #[serde(skip_serializing_if = "Option::is_none")]
60 pub rooms: Option<Vec<OwnedRoomId>>,
61
62 #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
67 pub not_senders: Vec<OwnedUserId>,
68
69 #[serde(skip_serializing_if = "Option::is_none")]
73 pub senders: Option<Vec<OwnedUserId>>,
74
75 #[serde(skip_serializing_if = "Option::is_none")]
80 pub types: Option<Vec<String>>,
81
82 #[serde(rename = "contains_url", skip_serializing_if = "Option::is_none")]
88 pub url_filter: Option<UrlFilter>,
89
90 #[serde(flatten)]
94 pub lazy_load_options: LazyLoadOptions,
95
96 #[serde(default, skip_serializing_if = "ruma_common::serde::is_default")]
103 pub unread_thread_notifications: bool,
104}
105
106impl RoomEventFilter {
107 pub fn empty() -> Self {
111 Self::default()
112 }
113
114 pub fn ignore_all() -> Self {
116 Self { types: Some(vec![]), ..Default::default() }
117 }
118
119 pub fn with_lazy_loading() -> Self {
125 Self {
126 lazy_load_options: LazyLoadOptions::Enabled { include_redundant_members: false },
127 ..Default::default()
128 }
129 }
130
131 pub fn is_empty(&self) -> bool {
133 self.not_types.is_empty()
134 && self.not_rooms.is_empty()
135 && self.limit.is_none()
136 && self.rooms.is_none()
137 && self.not_senders.is_empty()
138 && self.senders.is_none()
139 && self.types.is_none()
140 && self.url_filter.is_none()
141 && self.lazy_load_options.is_disabled()
142 && !self.unread_thread_notifications
143 }
144}
145
146#[derive(Clone, Debug, Default, Deserialize, Serialize)]
148#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
149pub struct RoomFilter {
150 #[serde(default, skip_serializing_if = "ruma_common::serde::is_default")]
154 pub include_leave: bool,
155
156 #[serde(default, skip_serializing_if = "ruma_common::serde::is_empty")]
158 pub account_data: RoomEventFilter,
159
160 #[serde(default, skip_serializing_if = "ruma_common::serde::is_empty")]
162 pub timeline: RoomEventFilter,
163
164 #[serde(default, skip_serializing_if = "ruma_common::serde::is_empty")]
167 pub ephemeral: RoomEventFilter,
168
169 #[serde(default, skip_serializing_if = "ruma_common::serde::is_empty")]
171 pub state: RoomEventFilter,
172
173 #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
179 pub not_rooms: Vec<OwnedRoomId>,
180
181 #[serde(skip_serializing_if = "Option::is_none")]
186 pub rooms: Option<Vec<OwnedRoomId>>,
187}
188
189impl RoomFilter {
190 pub fn empty() -> Self {
194 Self::default()
195 }
196
197 pub fn ignore_all() -> Self {
199 Self { rooms: Some(vec![]), ..Default::default() }
200 }
201
202 pub fn with_lazy_loading() -> Self {
208 Self { state: RoomEventFilter::with_lazy_loading(), ..Default::default() }
209 }
210
211 pub fn is_empty(&self) -> bool {
213 !self.include_leave
214 && self.account_data.is_empty()
215 && self.timeline.is_empty()
216 && self.ephemeral.is_empty()
217 && self.state.is_empty()
218 && self.not_rooms.is_empty()
219 && self.rooms.is_none()
220 }
221}
222
223#[derive(Clone, Debug, Default, Deserialize, Serialize)]
225#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
226pub struct Filter {
227 #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
233 pub not_types: Vec<String>,
234
235 #[serde(skip_serializing_if = "Option::is_none")]
237 pub limit: Option<UInt>,
238
239 #[serde(skip_serializing_if = "Option::is_none")]
243 pub senders: Option<Vec<OwnedUserId>>,
244
245 #[serde(skip_serializing_if = "Option::is_none")]
250 pub types: Option<Vec<String>>,
251
252 #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
257 pub not_senders: Vec<OwnedUserId>,
258}
259
260impl Filter {
261 pub fn empty() -> Self {
265 Self::default()
266 }
267
268 pub fn ignore_all() -> Self {
270 Self { types: Some(vec![]), ..Default::default() }
271 }
272
273 pub fn is_empty(&self) -> bool {
275 self.not_types.is_empty()
276 && self.limit.is_none()
277 && self.senders.is_none()
278 && self.types.is_none()
279 && self.not_senders.is_empty()
280 }
281}
282
283#[derive(Clone, Debug, Default, Deserialize, Serialize)]
285#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
286pub struct FilterDefinition {
287 #[serde(skip_serializing_if = "Option::is_none")]
294 pub event_fields: Option<Vec<String>>,
295
296 #[serde(default, skip_serializing_if = "ruma_common::serde::is_default")]
301 pub event_format: EventFormat,
302
303 #[serde(default, skip_serializing_if = "ruma_common::serde::is_empty")]
305 pub presence: Filter,
306
307 #[serde(default, skip_serializing_if = "ruma_common::serde::is_empty")]
309 pub account_data: Filter,
310
311 #[serde(default, skip_serializing_if = "ruma_common::serde::is_empty")]
313 pub room: RoomFilter,
314}
315
316impl FilterDefinition {
317 pub fn empty() -> Self {
321 Self::default()
322 }
323
324 pub fn ignore_all() -> Self {
326 Self {
327 account_data: Filter::ignore_all(),
328 room: RoomFilter::ignore_all(),
329 presence: Filter::ignore_all(),
330 ..Default::default()
331 }
332 }
333
334 pub fn with_lazy_loading() -> Self {
340 Self { room: RoomFilter::with_lazy_loading(), ..Default::default() }
341 }
342
343 pub fn is_empty(&self) -> bool {
345 self.event_fields.is_none()
346 && self.event_format == EventFormat::Client
347 && self.presence.is_empty()
348 && self.account_data.is_empty()
349 && self.room.is_empty()
350 }
351}
352
353macro_rules! can_be_empty {
354 ($ty:ident) => {
355 impl ruma_common::serde::CanBeEmpty for $ty {
356 fn is_empty(&self) -> bool {
357 self.is_empty()
358 }
359 }
360 };
361}
362
363can_be_empty!(Filter);
364can_be_empty!(FilterDefinition);
365can_be_empty!(RoomEventFilter);
366can_be_empty!(RoomFilter);
367
368#[cfg(test)]
369mod tests {
370 use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
371
372 use super::{
373 Filter, FilterDefinition, LazyLoadOptions, RoomEventFilter, RoomFilter, UrlFilter,
374 };
375
376 #[test]
377 fn default_filters_are_empty() -> serde_json::Result<()> {
378 assert_eq!(to_json_value(Filter::default())?, json!({}));
379 assert_eq!(to_json_value(FilterDefinition::default())?, json!({}));
380 assert_eq!(to_json_value(RoomEventFilter::default())?, json!({}));
381 assert_eq!(to_json_value(RoomFilter::default())?, json!({}));
382
383 Ok(())
384 }
385
386 #[test]
387 fn filter_definition_roundtrip() -> serde_json::Result<()> {
388 let filter = FilterDefinition::default();
389 let filter_str = to_json_value(&filter)?;
390
391 let incoming_filter = from_json_value::<FilterDefinition>(filter_str)?;
392 assert!(incoming_filter.is_empty());
393
394 Ok(())
395 }
396
397 #[test]
398 fn room_filter_definition_roundtrip() -> serde_json::Result<()> {
399 let filter = RoomFilter::default();
400 let room_filter = to_json_value(filter)?;
401
402 let incoming_room_filter = from_json_value::<RoomFilter>(room_filter)?;
403 assert!(incoming_room_filter.is_empty());
404
405 Ok(())
406 }
407
408 #[test]
409 fn issue_366() {
410 let obj = json!({
411 "lazy_load_members": true,
412 "filter_json": { "contains_url": true, "types": ["m.room.message"] },
413 "types": ["m.room.message"],
414 "not_types": [],
415 "rooms": null,
416 "not_rooms": [],
417 "senders": null,
418 "not_senders": [],
419 "contains_url": true,
420 });
421
422 let filter: RoomEventFilter = from_json_value(obj).unwrap();
423
424 assert_eq!(filter.types, Some(vec!["m.room.message".to_owned()]));
425 assert_eq!(filter.not_types, vec![""; 0]);
426 assert_eq!(filter.rooms, None);
427 assert_eq!(filter.not_rooms, vec![""; 0]);
428 assert_eq!(filter.senders, None);
429 assert_eq!(filter.not_senders, vec![""; 0]);
430 assert_eq!(filter.limit, None);
431 assert_eq!(filter.url_filter, Some(UrlFilter::EventsWithUrl));
432 assert_eq!(
433 filter.lazy_load_options,
434 LazyLoadOptions::Enabled { include_redundant_members: false }
435 );
436 }
437}