diff --git a/ruma-client-api/src/r0/context/get_context.rs b/ruma-client-api/src/r0/context/get_context.rs index 1d51ce4e..38f5833e 100644 --- a/ruma-client-api/src/r0/context/get_context.rs +++ b/ruma-client-api/src/r0/context/get_context.rs @@ -18,14 +18,15 @@ ruma_api! { requires_authentication: true, } + #[non_exhaustive] request: { /// The room to get events from. #[ruma_api(path)] - pub room_id: RoomId, + pub room_id: &'a RoomId, /// The event to get context around. #[ruma_api(path)] - pub event_id: EventId, + pub event_id: &'a EventId, /// The maximum number of events to return. /// @@ -44,6 +45,7 @@ ruma_api! { pub filter: Option, } + #[non_exhaustive] response: { /// A token that can be used to paginate backwards with. #[serde(skip_serializing_if = "Option::is_none")] @@ -75,6 +77,27 @@ ruma_api! { error: crate::Error } +impl<'a> Request<'a> { + /// Creates a new `Request` with the given room id and event id. + pub fn new(room_id: &'a RoomId, event_id: &'a EventId) -> Self { + Self { room_id, event_id, limit: default_limit(), filter: None } + } +} + +impl Response { + /// Creates an empty `Response`. + pub fn new() -> Self { + Self { + start: None, + end: None, + events_before: Vec::new(), + event: None, + events_after: Vec::new(), + state: Vec::new(), + } + } +} + fn default_limit() -> UInt { uint!(10) } diff --git a/ruma-client-api/src/r0/filter/create_filter.rs b/ruma-client-api/src/r0/filter/create_filter.rs index 61daa97b..b37ca3f5 100644 --- a/ruma-client-api/src/r0/filter/create_filter.rs +++ b/ruma-client-api/src/r0/filter/create_filter.rs @@ -15,18 +15,20 @@ ruma_api! { requires_authentication: true, } + #[non_exhaustive] request: { /// The ID of the user uploading the filter. /// /// The access token must be authorized to make requests for this user ID. #[ruma_api(path)] - pub user_id: UserId, + pub user_id: &'a UserId, /// The filter definition. #[ruma_api(body)] pub filter: FilterDefinition, } + #[non_exhaustive] response: { /// The ID of the filter that was created. pub filter_id: String, @@ -34,3 +36,17 @@ ruma_api! { error: crate::Error } + +impl<'a> Request<'a> { + /// Creates a new `Request` with the given user ID and filter definition. + pub fn new(user_id: &'a UserId, filter: FilterDefinition) -> Self { + Self { user_id, filter } + } +} + +impl Response { + /// Creates a new `Response` with the given filter ID. + pub fn new(filter_id: String) -> Self { + Self { filter_id } + } +} diff --git a/ruma-client-api/src/r0/filter/get_filter.rs b/ruma-client-api/src/r0/filter/get_filter.rs index e7684490..87b69f1b 100644 --- a/ruma-client-api/src/r0/filter/get_filter.rs +++ b/ruma-client-api/src/r0/filter/get_filter.rs @@ -15,16 +15,18 @@ ruma_api! { requires_authentication: true, } + #[non_exhaustive] request: { /// The user ID to download a filter for. #[ruma_api(path)] - pub user_id: UserId, + pub user_id: &'a UserId, /// The ID of the filter to download. #[ruma_api(path)] - pub filter_id: String, + pub filter_id: &'a str, } + #[non_exhaustive] response: { /// The filter definition. #[ruma_api(body)] @@ -33,3 +35,17 @@ ruma_api! { error: crate::Error } + +impl<'a> Request<'a> { + /// Creates a new `Request` with the given user ID and filter ID. + pub fn new(user_id: &'a UserId, filter_id: &'a str) -> Self { + Self { user_id, filter_id } + } +} + +impl Response { + /// Creates a new `Response` with the given filter definition. + pub fn new(filter: FilterDefinition) -> Self { + Self { filter } + } +} diff --git a/ruma-client-api/src/r0/message/get_message_events.rs b/ruma-client-api/src/r0/message/get_message_events.rs index a6ed4159..3427fcbb 100644 --- a/ruma-client-api/src/r0/message/get_message_events.rs +++ b/ruma-client-api/src/r0/message/get_message_events.rs @@ -23,7 +23,7 @@ ruma_api! { request: { /// The room to get events from. #[ruma_api(path)] - pub room_id: RoomId, + pub room_id: &'a RoomId, /// The token to start returning events from. /// @@ -31,7 +31,7 @@ ruma_api! { /// prev_batch token returned for each room by the sync API, or from a start or end token /// returned by a previous request to this endpoint. #[ruma_api(query)] - pub from: String, + pub from: &'a str, /// The token to stop returning events at. /// @@ -40,7 +40,7 @@ ruma_api! { /// by a previous request to this endpoint. #[serde(skip_serializing_if = "Option::is_none")] #[ruma_api(query)] - pub to: Option, + pub to: Option<&'a str>, /// The direction to return events from. #[ruma_api(query)] @@ -63,6 +63,7 @@ ruma_api! { pub filter: Option, } + #[non_exhaustive] response: { /// The token the pagination starts from. #[serde(skip_serializing_if = "Option::is_none")] @@ -84,15 +85,22 @@ ruma_api! { error: crate::Error } -impl Request { +impl<'a> Request<'a> { /// Creates a `Request` with the given parameters. /// /// All other parameters will be defaulted. - pub fn new(room_id: RoomId, from: String, dir: Direction) -> Self { + pub fn new(room_id: &'a RoomId, from: &'a str, dir: Direction) -> Self { Self { room_id, from, to: None, dir, limit: default_limit(), filter: None } } } +impl Response { + /// Creates an empty `Response`. + pub fn new() -> Self { + Self { start: None, end: None, chunk: Vec::new(), state: Vec::new() } + } +} + fn default_limit() -> UInt { uint!(10) } @@ -135,9 +143,9 @@ mod tests { ..Default::default() }; let req = Request { - room_id, - from: "token".into(), - to: Some("token2".into()), + room_id: &room_id, + from: "token", + to: Some("token2"), dir: Direction::Backward, limit: uint!(0), filter: Some(filter), @@ -161,9 +169,9 @@ mod tests { fn test_serialize_none_room_event_filter() { let room_id = room_id!("!roomid:example.org"); let req = Request { - room_id, - from: "token".into(), - to: Some("token2".into()), + room_id: &room_id, + from: "token", + to: Some("token2"), dir: Direction::Backward, limit: uint!(0), filter: None, @@ -178,9 +186,9 @@ mod tests { fn test_serialize_default_room_event_filter() { let room_id = room_id!("!roomid:example.org"); let req = Request { - room_id, - from: "token".into(), - to: Some("token2".into()), + room_id: &room_id, + from: "token", + to: Some("token2"), dir: Direction::Backward, limit: uint!(0), filter: Some(RoomEventFilter::default()), diff --git a/ruma-client-api/src/r0/search/search_events.rs b/ruma-client-api/src/r0/search/search_events.rs index 9237bf99..65117056 100644 --- a/ruma-client-api/src/r0/search/search_events.rs +++ b/ruma-client-api/src/r0/search/search_events.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use js_int::{uint, UInt}; -use ruma_api::ruma_api; +use ruma_api::{ruma_api, Outgoing}; use ruma_common::Raw; use ruma_events::{AnyEvent, AnyStateEvent}; use ruma_identifiers::{EventId, RoomId, UserId}; @@ -21,17 +21,19 @@ ruma_api! { requires_authentication: true, } + #[non_exhaustive] request: { /// The point to return events from. /// /// If given, this should be a `next_batch` result from a previous call to this endpoint. #[ruma_api(query)] - pub next_batch: Option, + pub next_batch: Option<&'a str>, /// Describes which categories to search in and their criteria. - pub search_categories: Categories, + pub search_categories: Categories<'a>, } + #[non_exhaustive] response: { /// A grouping of search results by category. pub search_categories: ResultCategories, @@ -40,23 +42,45 @@ ruma_api! { error: crate::Error } +impl<'a> Request<'a> { + /// Creates a new `Request` with the given categories. + pub fn new(search_categories: Categories<'a>) -> Self { + Self { next_batch: None, search_categories } + } +} + +impl Response { + /// Creates a new `Response` with the given search results. + pub fn new(search_categories: ResultCategories) -> Self { + Self { search_categories } + } +} + /// Categories of events that can be searched for. -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct Categories { - /// Criteria for searching a category of events. +#[derive(Clone, Debug, Outgoing, Serialize)] +#[non_exhaustive] +pub struct Categories<'a> { + /// Criteria for searching room events. #[serde(skip_serializing_if = "Option::is_none")] - pub room_events: Option, + pub room_events: Option>, +} + +impl<'a> Categories<'a> { + /// Creates an empty `Categories`. + pub fn new() -> Self { + Self { room_events: None } + } } /// Criteria for searching a category of events. -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct Criteria { +#[derive(Clone, Debug, Outgoing, Serialize)] +pub struct Criteria<'a> { /// The string to search events for. - pub search_term: String, + pub search_term: &'a str, /// The keys to search for. Defaults to all keys. #[serde(skip_serializing_if = "Option::is_none")] - pub keys: Option>, + pub keys: Option<&'a [SearchKeys]>, /// A `Filter` to apply to the search. #[serde(skip_serializing_if = "Option::is_none")] @@ -76,7 +100,7 @@ pub struct Criteria { /// Requests that the server partitions the result set based on the provided list of keys. #[serde(skip_serializing_if = "Option::is_none")] - pub groupings: Option, + pub groupings: Option>, } /// Configures whether any context for the events returned are included in the response. @@ -154,11 +178,11 @@ pub enum GroupingKey { } /// Requests that the server partitions the result set based on the provided list of keys. -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct Groupings { +#[derive(Clone, Copy, Debug, Outgoing, Serialize)] +pub struct Groupings<'a> { /// List of groups to request. - #[serde(default, skip_serializing_if = "Vec::is_empty")] - pub group_by: Vec, + #[serde(default, skip_serializing_if = "<[_]>::is_empty")] + pub group_by: &'a [Grouping], } /// The keys to search for. diff --git a/ruma-client-api/src/r0/server/get_user_info.rs b/ruma-client-api/src/r0/server/get_user_info.rs index 02a2367b..134497c2 100644 --- a/ruma-client-api/src/r0/server/get_user_info.rs +++ b/ruma-client-api/src/r0/server/get_user_info.rs @@ -16,12 +16,14 @@ ruma_api! { requires_authentication: true, } + #[non_exhaustive] request: { /// The user to look up. #[ruma_api(path)] - pub user_id: UserId, + pub user_id: &'a UserId, } + #[non_exhaustive] response: { /// The Matrix user ID of the user. #[serde(skip_serializing_if = "Option::is_none")] @@ -35,6 +37,20 @@ ruma_api! { error: crate::Error } +impl<'a> Request<'a> { + /// Creates a new `Request` with the given user id. + pub fn new(user_id: &'a UserId) -> Self { + Self { user_id } + } +} + +impl Response { + /// Creates an empty `Response`. + pub fn new() -> Self { + Self { user_id: None, devices: BTreeMap::new() } + } +} + /// Information about a user's device. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct DeviceInfo { diff --git a/ruma-client-api/src/r0/session/login.rs b/ruma-client-api/src/r0/session/login.rs index 0513cf8e..1aaf2182 100644 --- a/ruma-client-api/src/r0/session/login.rs +++ b/ruma-client-api/src/r0/session/login.rs @@ -64,7 +64,7 @@ ruma_api! { } /// Identification information for the user. -#[derive(Clone, Debug, PartialEq, Eq, Outgoing, Serialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Outgoing, Serialize)] #[serde(from = "user_serde::IncomingUserInfo", into = "user_serde::UserInfo")] pub enum UserInfo<'a> { /// Either a fully qualified Matrix user ID, or just the localpart (as part of the 'identifier' @@ -92,7 +92,7 @@ pub enum UserInfo<'a> { } /// The authentication mechanism. -#[derive(Clone, Debug, PartialEq, Eq, Outgoing, Serialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Outgoing, Serialize)] #[serde(tag = "type")] pub enum LoginInfo<'a> { /// A password is supplied to authenticate. diff --git a/ruma-client-api/src/r0/sync/sync_events.rs b/ruma-client-api/src/r0/sync/sync_events.rs index 8f62e233..c4bea870 100644 --- a/ruma-client-api/src/r0/sync/sync_events.rs +++ b/ruma-client-api/src/r0/sync/sync_events.rs @@ -3,7 +3,7 @@ use std::{collections::BTreeMap, time::Duration}; use js_int::UInt; -use ruma_api::ruma_api; +use ruma_api::{ruma_api, Outgoing}; use ruma_common::{presence::PresenceState, Raw}; use ruma_events::{ presence::PresenceEvent, AnyBasicEvent, AnyStrippedStateEvent, AnySyncEphemeralRoomEvent, @@ -28,7 +28,7 @@ ruma_api! { /// A filter represented either as its full JSON definition or the ID of a saved filter. #[serde(skip_serializing_if = "Option::is_none")] #[ruma_api(query)] - pub filter: Option, + pub filter: Option>, /// A point in time to continue a sync from. /// @@ -36,7 +36,7 @@ ruma_api! { /// request. #[serde(skip_serializing_if = "Option::is_none")] #[ruma_api(query)] - pub since: Option, + pub since: Option<&'a str>, /// Controls whether to include the full state for all rooms the user is a member of. #[serde(default, skip_serializing_if = "ruma_serde::is_default")] @@ -94,10 +94,10 @@ ruma_api! { } /// A filter represented either as its full JSON definition or the ID of a saved filter. -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Outgoing, Serialize)] #[allow(clippy::large_enum_variant)] #[serde(untagged)] -pub enum Filter { +pub enum Filter<'a> { // The filter definition needs to be (de)serialized twice because it is a URL-encoded JSON // string. Since #[ruma_api(query)] only does the latter and this is a very uncommon // setup, we implement it through custom serde logic for this specific enum variant rather than @@ -113,7 +113,7 @@ pub enum Filter { FilterDefinition(FilterDefinition), /// The ID of a filter saved on the server. - FilterId(String), + FilterId(&'a str), } /// Updates to rooms. @@ -408,13 +408,13 @@ mod tests { use matches::assert_matches; - use super::{Filter, PresenceState, Request, Timeline}; + use super::{Filter, IncomingFilter, IncomingRequest, PresenceState, Request, Timeline}; #[test] fn serialize_all_params() { let req: http::Request> = Request { - filter: Some(Filter::FilterId("66696p746572".into())), - since: Some("s72594_4483_1934".into()), + filter: Some(Filter::FilterId("66696p746572")), + since: Some("s72594_4483_1934"), full_state: true, set_presence: PresenceState::Offline, timeout: Some(Duration::from_millis(30000)), @@ -449,10 +449,10 @@ mod tests { .build() .unwrap(); - let req: Request = + let req: IncomingRequest = http::Request::builder().uri(uri).body(Vec::::new()).unwrap().try_into().unwrap(); - assert_matches!(req.filter, Some(Filter::FilterId(id)) if id == "myfilter"); + assert_matches!(req.filter, Some(IncomingFilter::FilterId(id)) if id == "myfilter"); assert_eq!(req.since, Some("myts".into())); assert_eq!(req.full_state, false); assert_eq!(req.set_presence, PresenceState::Offline); @@ -468,7 +468,7 @@ mod tests { .build() .unwrap(); - let req: Request = + let req: IncomingRequest = http::Request::builder().uri(uri).body(Vec::::new()).unwrap().try_into().unwrap(); assert_matches!(req.filter, None); @@ -491,10 +491,10 @@ mod tests { .build() .unwrap(); - let req: Request = + let req: IncomingRequest = http::Request::builder().uri(uri).body(Vec::::new()).unwrap().try_into().unwrap(); - assert_matches!(req.filter, Some(Filter::FilterId(id)) if id == "EOKFFmdZYF"); + assert_matches!(req.filter, Some(IncomingFilter::FilterId(id)) if id == "EOKFFmdZYF"); assert_eq!(req.since, None); assert_eq!(req.full_state, false); assert_eq!(req.set_presence, PresenceState::Online); diff --git a/ruma-client/src/lib.rs b/ruma-client/src/lib.rs index 58dacbcf..b47e1ea8 100644 --- a/ruma-client/src/lib.rs +++ b/ruma-client/src/lib.rs @@ -319,24 +319,25 @@ where /// If the since parameter is None, the first Item might take a significant time to arrive and /// be deserialized, because it contains all events that have occurred in the whole lifetime of /// the logged-in users account and are visible to them. - pub fn sync( + pub fn sync<'a>( &self, - filter: Option, + filter: Option>, since: Option, set_presence: ruma_common::presence::PresenceState, timeout: Option, ) -> impl Stream>> - + TryStream> { + + TryStream> + + 'a { let client = self.clone(); stream::try_unfold(since, move |since| { let client = client.clone(); - let filter = filter.clone(); + let filter = filter.clone(); // FIXME: Remove once `SyncFilter` is `Copy` async move { let response = client .request(SyncRequest { filter, - since, + since: since.as_deref(), full_state: false, set_presence, timeout,