client-api: Use Option less for event filters

This commit is contained in:
Jonas Platte 2020-10-17 22:34:20 +02:00
parent aa43d47343
commit a67a396ee0
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
2 changed files with 187 additions and 29 deletions

View File

@ -14,8 +14,9 @@ use ruma_common::Outgoing;
use ruma_identifiers::{RoomId, UserId}; use ruma_identifiers::{RoomId, UserId};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// Format to use for returned events /// Format to use for returned events.
#[derive(Copy, Clone, Debug, Deserialize, Serialize)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum EventFormat { pub enum EventFormat {
/// Client format, as described in the Client API. /// Client format, as described in the Client API.
@ -25,8 +26,15 @@ pub enum EventFormat {
Federation, Federation,
} }
/// Filters to be applied to room events impl Default for EventFormat {
fn default() -> Self {
Self::Client
}
}
/// Filters to be applied to room events.
#[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)] #[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[incoming_derive(Clone, Serialize)] #[incoming_derive(Clone, Serialize)]
pub struct RoomEventFilter<'a> { pub struct RoomEventFilter<'a> {
/// A list of event types to exclude. /// A list of event types to exclude.
@ -88,14 +96,50 @@ pub struct RoomEventFilter<'a> {
} }
impl<'a> RoomEventFilter<'a> { impl<'a> RoomEventFilter<'a> {
/// A filter that can be used to ignore all room events /// Creates an empty `RoomEventFilter`.
///
/// You can also use the [`Default`] implementation.
pub fn empty() -> Self {
Self::default()
}
/// Creates a `RoomEventFilter` that can be used to ignore all room events.
pub fn ignore_all() -> Self { pub fn ignore_all() -> Self {
Self { types: Some(&[]), ..Default::default() } Self { types: Some(&[]), ..Default::default() }
} }
/// Returns `true` if all fields are empty.
pub fn is_empty(&self) -> bool {
self.not_types.is_empty()
&& self.not_rooms.is_empty()
&& self.limit.is_none()
&& self.rooms.is_none()
&& self.not_senders.is_empty()
&& self.senders.is_none()
&& self.types.is_none()
&& self.url_filter.is_none()
&& self.lazy_load_options.is_disabled()
}
} }
/// Filters to be applied to room data impl IncomingRoomEventFilter {
/// Returns `true` if all fields are empty.
pub fn is_empty(&self) -> bool {
self.not_types.is_empty()
&& self.not_rooms.is_empty()
&& self.limit.is_none()
&& self.rooms.is_none()
&& self.not_senders.is_empty()
&& self.senders.is_none()
&& self.types.is_none()
&& self.url_filter.is_none()
&& self.lazy_load_options.is_disabled()
}
}
/// Filters to be applied to room data.
#[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)] #[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[incoming_derive(Clone, Serialize)] #[incoming_derive(Clone, Serialize)]
pub struct RoomFilter<'a> { pub struct RoomFilter<'a> {
/// Include rooms that the user has left in the sync. /// Include rooms that the user has left in the sync.
@ -105,21 +149,21 @@ pub struct RoomFilter<'a> {
pub include_leave: bool, pub include_leave: bool,
/// The per user account data to include for rooms. /// The per user account data to include for rooms.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "ruma_serde::is_empty")]
pub account_data: Option<RoomEventFilter<'a>>, pub account_data: RoomEventFilter<'a>,
/// The message and state update events to include for rooms. /// The message and state update events to include for rooms.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "ruma_serde::is_empty")]
pub timeline: Option<RoomEventFilter<'a>>, pub timeline: RoomEventFilter<'a>,
/// The events that aren't recorded in the room history, e.g. typing and receipts, to include /// The events that aren't recorded in the room history, e.g. typing and receipts, to include
/// for rooms. /// for rooms.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "ruma_serde::is_empty")]
pub ephemeral: Option<RoomEventFilter<'a>>, pub ephemeral: RoomEventFilter<'a>,
/// The state events to include for rooms. /// The state events to include for rooms.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "ruma_serde::is_empty")]
pub state: Option<RoomEventFilter<'a>>, pub state: RoomEventFilter<'a>,
/// A list of room IDs to exclude. /// A list of room IDs to exclude.
/// ///
@ -138,14 +182,46 @@ pub struct RoomFilter<'a> {
} }
impl<'a> RoomFilter<'a> { impl<'a> RoomFilter<'a> {
/// A filter that can be used to ignore all room events (of any type) /// Creates an empty `RoomFilter`.
///
/// You can also use the [`Default`] implementation.
pub fn empty() -> Self {
Self::default()
}
/// Creates a `RoomFilter` that can be used to ignore all room events (of any type).
pub fn ignore_all() -> Self { pub fn ignore_all() -> Self {
Self { rooms: Some(&[]), ..Default::default() } Self { rooms: Some(&[]), ..Default::default() }
} }
/// Returns `true` if all fields are empty.
pub fn is_empty(&self) -> bool {
!self.include_leave
&& self.account_data.is_empty()
&& self.timeline.is_empty()
&& self.ephemeral.is_empty()
&& self.state.is_empty()
&& self.not_rooms.is_empty()
&& self.rooms.is_none()
}
} }
/// Filter for not-room data impl IncomingRoomFilter {
/// Returns `true` if all fields are empty.
pub fn is_empty(&self) -> bool {
!self.include_leave
&& self.account_data.is_empty()
&& self.timeline.is_empty()
&& self.ephemeral.is_empty()
&& self.state.is_empty()
&& self.not_rooms.is_empty()
&& self.rooms.is_none()
}
}
/// Filter for non-room data.
#[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)] #[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[incoming_derive(Clone, Serialize)] #[incoming_derive(Clone, Serialize)]
pub struct Filter<'a> { pub struct Filter<'a> {
/// A list of event types to exclude. /// A list of event types to exclude.
@ -182,14 +258,42 @@ pub struct Filter<'a> {
} }
impl<'a> Filter<'a> { impl<'a> Filter<'a> {
/// A filter that can be used to ignore all events /// Creates an empty `Filter`.
///
/// You can also use the [`Default`] implementation.
pub fn empty() -> Self {
Self::default()
}
/// Creates a `Filter` that can be used to ignore all events.
pub fn ignore_all() -> Self { pub fn ignore_all() -> Self {
Self { types: Some(&[]), ..Default::default() } Self { types: Some(&[]), ..Default::default() }
} }
/// Returns `true` if all fields are empty.
pub fn is_empty(&self) -> bool {
self.not_types.is_empty()
&& self.limit.is_none()
&& self.senders.is_none()
&& self.types.is_none()
&& self.not_senders.is_empty()
}
}
impl IncomingFilter {
/// Returns `true` if all fields are empty.
pub fn is_empty(&self) -> bool {
self.not_types.is_empty()
&& self.limit.is_none()
&& self.senders.is_none()
&& self.types.is_none()
&& self.not_senders.is_empty()
}
} }
/// A filter definition /// A filter definition
#[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)] #[derive(Clone, Copy, Debug, Default, Outgoing, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[incoming_derive(Clone, Serialize)] #[incoming_derive(Clone, Serialize)]
pub struct FilterDefinition<'a> { pub struct FilterDefinition<'a> {
/// List of event fields to include. /// List of event fields to include.
@ -198,40 +302,87 @@ pub struct FilterDefinition<'a> {
/// to indicate sub-fields. So ['content.body'] will include the 'body' field of the 'content' /// to indicate sub-fields. So ['content.body'] will include the 'body' field of the 'content'
/// object. A literal '.' character in a field name may be escaped using a '\'. A server may /// object. A literal '.' character in a field name may be escaped using a '\'. A server may
/// include more fields than were requested. /// include more fields than were requested.
#[serde(default, skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub event_fields: Option<&'a [String]>, pub event_fields: Option<&'a [String]>,
/// The format to use for events. /// The format to use for events.
/// ///
/// 'client' will return the events in a format suitable for clients. 'federation' will return /// 'client' will return the events in a format suitable for clients. 'federation' will return
/// the raw event as received over federation. The default is 'client'. /// the raw event as received over federation. The default is 'client'.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(default, skip_serializing_if = "ruma_serde::is_default")]
pub event_format: Option<EventFormat>, pub event_format: EventFormat,
/// The presence updates to include. /// The presence updates to include.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "ruma_serde::is_empty")]
pub presence: Option<Filter<'a>>, pub presence: Filter<'a>,
/// The user account data that isn't associated with rooms to include. /// The user account data that isn't associated with rooms to include.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "ruma_serde::is_empty")]
pub account_data: Option<Filter<'a>>, pub account_data: Filter<'a>,
/// Filters to be applied to room data. /// Filters to be applied to room data.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "ruma_serde::is_empty")]
pub room: Option<RoomFilter<'a>>, pub room: RoomFilter<'a>,
} }
impl<'a> FilterDefinition<'a> { impl<'a> FilterDefinition<'a> {
/// A filter that can be used to ignore all events /// Creates an empty `FilterDefinition`.
///
/// You can also use the [`Default`] implementation.
pub fn empty() -> Self {
Self::default()
}
/// Creates a `FilterDefinition` that can be used to ignore all events.
pub fn ignore_all() -> Self { pub fn ignore_all() -> Self {
Self { Self {
account_data: Some(Filter::ignore_all()), account_data: Filter::ignore_all(),
room: Some(RoomFilter::ignore_all()), room: RoomFilter::ignore_all(),
presence: Some(Filter::ignore_all()), presence: Filter::ignore_all(),
..Default::default() ..Default::default()
} }
} }
/// Returns `true` if all fields are empty.
pub fn is_empty(&self) -> bool {
self.event_fields.is_none()
&& self.event_format == EventFormat::Client
&& self.presence.is_empty()
&& self.account_data.is_empty()
&& self.room.is_empty()
} }
}
impl IncomingFilterDefinition {
/// Returns `true` if all fields are empty.
pub fn is_empty(&self) -> bool {
self.event_fields.is_none()
&& self.event_format == EventFormat::Client
&& self.presence.is_empty()
&& self.account_data.is_empty()
&& self.room.is_empty()
}
}
macro_rules! can_be_empty {
($ty:ident $(<$gen:tt>)?) => {
impl $(<$gen>)? ruma_serde::CanBeEmpty for $ty $(<$gen>)? {
fn is_empty(&self) -> bool {
self.is_empty()
}
}
};
}
can_be_empty!(Filter<'a>);
can_be_empty!(FilterDefinition<'a>);
can_be_empty!(RoomEventFilter<'a>);
can_be_empty!(RoomFilter<'a>);
can_be_empty!(IncomingFilter);
can_be_empty!(IncomingFilterDefinition);
can_be_empty!(IncomingRoomEventFilter);
can_be_empty!(IncomingRoomFilter);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -22,6 +22,13 @@ pub enum LazyLoadOptions {
}, },
} }
impl LazyLoadOptions {
/// Returns `true` is `self` is `Disabled`.
pub fn is_disabled(&self) -> bool {
matches!(self, Self::Disabled)
}
}
impl Serialize for LazyLoadOptions { impl Serialize for LazyLoadOptions {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where