common: Replace BTreeSet by IndexSet in push::Ruleset.

Keeps the JSON ordering for priority.

IndexSet are hashed by `rule_id` so its uniqueness is enforced.

A rule can be fetched by its `rule_id`.
This commit is contained in:
Kévin Commaille 2021-03-21 10:50:40 +01:00 committed by Jonas Platte
parent acb7fdd647
commit 22f7f28e1b
4 changed files with 35 additions and 29 deletions

View File

@ -3,6 +3,7 @@
Breaking changes:
* Update set of conversion trait implementations for enums
* Replace `BTreeSet` by `IndexSet` in `push::Ruleset`.
* … (there's a lot more, but this changelog was not kept up to date; PRs to
improve it are welcome)

View File

@ -17,6 +17,7 @@ ruma-identifiers = { version = "=0.18.0-alpha.1", path = "../ruma-identifiers" }
ruma-serde = { version = "0.3.0", path = "../ruma-serde" }
serde = { version = "1.0.118", features = ["derive"] }
serde_json = { version = "1.0.60", features = ["raw_value"] }
indexmap = { version = "1.6.2", features = ["serde-1"] }
[dev-dependencies]
matches = "0.1.8"

View File

@ -6,13 +6,13 @@
//!
//! Push rules are grouped in `RuleSet`s, and are grouped in five kinds (for
//! more details about the different kind of rules, see the `Ruleset` documentation,
//! or the specification). These five kinds are:
//! or the specification). These five kinds are, by order of priority:
//!
//! - content rules
//! - override rules
//! - underride rules
//! - content rules
//! - room rules
//! - sender rules
//! - underride rules
//!
//! Each of these kind of rule has a corresponding type that is
//! just a wrapper around another type:
@ -34,8 +34,12 @@
//! There is also the `AnyPushRule` type that is the most generic form of push rule, with all
//! the possible fields.
use std::collections::btree_set::{BTreeSet, IntoIter as BTreeSetIter};
use std::hash::{Hash, Hasher};
use indexmap::{
set::{IndexSet, IntoIter as IndexSetIter},
Equivalent,
};
use ruma_serde::StringEnum;
use serde::{Deserialize, Serialize};
@ -58,24 +62,24 @@ pub use self::{
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Ruleset {
/// These rules configure behavior for (unencrypted) messages that match certain patterns.
pub content: BTreeSet<ContentPushRule>,
pub content: IndexSet<ContentPushRule>,
/// These user-configured rules are given the highest priority.
///
/// This field is named `override_` instead of `override` because the latter is a reserved
/// keyword in Rust.
#[serde(rename = "override")]
pub override_: BTreeSet<OverridePushRule>,
pub override_: IndexSet<OverridePushRule>,
/// These rules change the behavior of all messages for a given room.
pub room: BTreeSet<RoomPushRule>,
pub room: IndexSet<RoomPushRule>,
/// These rules configure notification behavior for messages from a specific Matrix user ID.
pub sender: BTreeSet<SenderPushRule>,
pub sender: IndexSet<SenderPushRule>,
/// These rules are identical to override rules, but have a lower priority than `content`,
/// `room` and `sender` rules.
pub underride: BTreeSet<UnderridePushRule>,
pub underride: IndexSet<UnderridePushRule>,
}
impl Ruleset {
@ -97,11 +101,11 @@ impl Ruleset {
/// Iterator type for `Ruleset`
#[derive(Debug)]
pub struct RulesetIter {
content: BTreeSetIter<ContentPushRule>,
override_: BTreeSetIter<OverridePushRule>,
room: BTreeSetIter<RoomPushRule>,
sender: BTreeSetIter<SenderPushRule>,
underride: BTreeSetIter<UnderridePushRule>,
content: IndexSetIter<ContentPushRule>,
override_: IndexSetIter<OverridePushRule>,
room: IndexSetIter<RoomPushRule>,
sender: IndexSetIter<SenderPushRule>,
underride: IndexSetIter<UnderridePushRule>,
}
impl Iterator for RulesetIter {
@ -180,17 +184,11 @@ macro_rules! rulekind {
}
// The following trait are needed to be able to make
// a BTreeSet of the new type
// an IndexSet of the new type
impl Ord for $name {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.0.rule_id.cmp(&other.0.rule_id)
}
}
impl PartialOrd for $name {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
impl Hash for $name {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.rule_id.hash(state);
}
}
@ -201,6 +199,12 @@ macro_rules! rulekind {
}
impl Eq for $name {}
impl Equivalent<$name> for str {
fn equivalent(&self, key: &$name) -> bool {
self == key.0.rule_id
}
}
};
}

View File

@ -1,7 +1,7 @@
///! Constructors for [predefined push rules].
///!
///! [predefined push rules]: https://matrix.org/docs/spec/client_server/r0.6.1#predefined-rules
use maplit::btreeset;
use indexmap::indexset;
use ruma_identifiers::UserId;
use super::{
@ -20,9 +20,9 @@ impl Ruleset {
/// user's ID (for instance those to send notifications when they are mentioned).
pub fn server_default(user_id: &UserId) -> Self {
Self {
content: btreeset![ContentPushRule::contains_user_name(user_id)],
content: indexset![ContentPushRule::contains_user_name(user_id)],
#[cfg(feature = "unstable-pre-spec")]
override_: btreeset![
override_: indexset![
OverridePushRule::master(),
OverridePushRule::suppress_notices(),
OverridePushRule::invite_for_me(user_id),
@ -33,7 +33,7 @@ impl Ruleset {
OverridePushRule::reaction(),
],
#[cfg(not(feature = "unstable-pre-spec"))]
override_: btreeset![
override_: indexset![
OverridePushRule::master(),
OverridePushRule::suppress_notices(),
OverridePushRule::invite_for_me(user_id),
@ -42,7 +42,7 @@ impl Ruleset {
OverridePushRule::tombstone(),
OverridePushRule::roomnotif(),
],
underride: btreeset![
underride: indexset![
UnderridePushRule::call(),
UnderridePushRule::encrypted_room_one_to_one(),
UnderridePushRule::room_one_to_one(),