client-api: More borrowing

This commit is contained in:
Jonas Platte 2020-08-14 01:28:05 +02:00
parent 7557ed438b
commit d6c15e5769
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
9 changed files with 161 additions and 57 deletions

View File

@ -18,14 +18,15 @@ ruma_api! {
requires_authentication: true, requires_authentication: true,
} }
#[non_exhaustive]
request: { request: {
/// The room to get events from. /// The room to get events from.
#[ruma_api(path)] #[ruma_api(path)]
pub room_id: RoomId, pub room_id: &'a RoomId,
/// The event to get context around. /// The event to get context around.
#[ruma_api(path)] #[ruma_api(path)]
pub event_id: EventId, pub event_id: &'a EventId,
/// The maximum number of events to return. /// The maximum number of events to return.
/// ///
@ -44,6 +45,7 @@ ruma_api! {
pub filter: Option<RoomEventFilter>, pub filter: Option<RoomEventFilter>,
} }
#[non_exhaustive]
response: { response: {
/// A token that can be used to paginate backwards with. /// A token that can be used to paginate backwards with.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
@ -75,6 +77,27 @@ ruma_api! {
error: crate::Error 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 { fn default_limit() -> UInt {
uint!(10) uint!(10)
} }

View File

@ -15,18 +15,20 @@ ruma_api! {
requires_authentication: true, requires_authentication: true,
} }
#[non_exhaustive]
request: { request: {
/// The ID of the user uploading the filter. /// The ID of the user uploading the filter.
/// ///
/// The access token must be authorized to make requests for this user ID. /// The access token must be authorized to make requests for this user ID.
#[ruma_api(path)] #[ruma_api(path)]
pub user_id: UserId, pub user_id: &'a UserId,
/// The filter definition. /// The filter definition.
#[ruma_api(body)] #[ruma_api(body)]
pub filter: FilterDefinition, pub filter: FilterDefinition,
} }
#[non_exhaustive]
response: { response: {
/// The ID of the filter that was created. /// The ID of the filter that was created.
pub filter_id: String, pub filter_id: String,
@ -34,3 +36,17 @@ ruma_api! {
error: crate::Error 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 }
}
}

View File

@ -15,16 +15,18 @@ ruma_api! {
requires_authentication: true, requires_authentication: true,
} }
#[non_exhaustive]
request: { request: {
/// The user ID to download a filter for. /// The user ID to download a filter for.
#[ruma_api(path)] #[ruma_api(path)]
pub user_id: UserId, pub user_id: &'a UserId,
/// The ID of the filter to download. /// The ID of the filter to download.
#[ruma_api(path)] #[ruma_api(path)]
pub filter_id: String, pub filter_id: &'a str,
} }
#[non_exhaustive]
response: { response: {
/// The filter definition. /// The filter definition.
#[ruma_api(body)] #[ruma_api(body)]
@ -33,3 +35,17 @@ ruma_api! {
error: crate::Error 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 }
}
}

View File

@ -23,7 +23,7 @@ ruma_api! {
request: { request: {
/// The room to get events from. /// The room to get events from.
#[ruma_api(path)] #[ruma_api(path)]
pub room_id: RoomId, pub room_id: &'a RoomId,
/// The token to start returning events from. /// 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 /// 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. /// returned by a previous request to this endpoint.
#[ruma_api(query)] #[ruma_api(query)]
pub from: String, pub from: &'a str,
/// The token to stop returning events at. /// The token to stop returning events at.
/// ///
@ -40,7 +40,7 @@ ruma_api! {
/// by a previous request to this endpoint. /// by a previous request to this endpoint.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[ruma_api(query)] #[ruma_api(query)]
pub to: Option<String>, pub to: Option<&'a str>,
/// The direction to return events from. /// The direction to return events from.
#[ruma_api(query)] #[ruma_api(query)]
@ -63,6 +63,7 @@ ruma_api! {
pub filter: Option<RoomEventFilter>, pub filter: Option<RoomEventFilter>,
} }
#[non_exhaustive]
response: { response: {
/// The token the pagination starts from. /// The token the pagination starts from.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
@ -84,15 +85,22 @@ ruma_api! {
error: crate::Error error: crate::Error
} }
impl Request { impl<'a> Request<'a> {
/// Creates a `Request` with the given parameters. /// Creates a `Request` with the given parameters.
/// ///
/// All other parameters will be defaulted. /// 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 } 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 { fn default_limit() -> UInt {
uint!(10) uint!(10)
} }
@ -135,9 +143,9 @@ mod tests {
..Default::default() ..Default::default()
}; };
let req = Request { let req = Request {
room_id, room_id: &room_id,
from: "token".into(), from: "token",
to: Some("token2".into()), to: Some("token2"),
dir: Direction::Backward, dir: Direction::Backward,
limit: uint!(0), limit: uint!(0),
filter: Some(filter), filter: Some(filter),
@ -161,9 +169,9 @@ mod tests {
fn test_serialize_none_room_event_filter() { fn test_serialize_none_room_event_filter() {
let room_id = room_id!("!roomid:example.org"); let room_id = room_id!("!roomid:example.org");
let req = Request { let req = Request {
room_id, room_id: &room_id,
from: "token".into(), from: "token",
to: Some("token2".into()), to: Some("token2"),
dir: Direction::Backward, dir: Direction::Backward,
limit: uint!(0), limit: uint!(0),
filter: None, filter: None,
@ -178,9 +186,9 @@ mod tests {
fn test_serialize_default_room_event_filter() { fn test_serialize_default_room_event_filter() {
let room_id = room_id!("!roomid:example.org"); let room_id = room_id!("!roomid:example.org");
let req = Request { let req = Request {
room_id, room_id: &room_id,
from: "token".into(), from: "token",
to: Some("token2".into()), to: Some("token2"),
dir: Direction::Backward, dir: Direction::Backward,
limit: uint!(0), limit: uint!(0),
filter: Some(RoomEventFilter::default()), filter: Some(RoomEventFilter::default()),

View File

@ -3,7 +3,7 @@
use std::collections::BTreeMap; use std::collections::BTreeMap;
use js_int::{uint, UInt}; use js_int::{uint, UInt};
use ruma_api::ruma_api; use ruma_api::{ruma_api, Outgoing};
use ruma_common::Raw; use ruma_common::Raw;
use ruma_events::{AnyEvent, AnyStateEvent}; use ruma_events::{AnyEvent, AnyStateEvent};
use ruma_identifiers::{EventId, RoomId, UserId}; use ruma_identifiers::{EventId, RoomId, UserId};
@ -21,17 +21,19 @@ ruma_api! {
requires_authentication: true, requires_authentication: true,
} }
#[non_exhaustive]
request: { request: {
/// The point to return events from. /// The point to return events from.
/// ///
/// If given, this should be a `next_batch` result from a previous call to this endpoint. /// If given, this should be a `next_batch` result from a previous call to this endpoint.
#[ruma_api(query)] #[ruma_api(query)]
pub next_batch: Option<String>, pub next_batch: Option<&'a str>,
/// Describes which categories to search in and their criteria. /// Describes which categories to search in and their criteria.
pub search_categories: Categories, pub search_categories: Categories<'a>,
} }
#[non_exhaustive]
response: { response: {
/// A grouping of search results by category. /// A grouping of search results by category.
pub search_categories: ResultCategories, pub search_categories: ResultCategories,
@ -40,23 +42,45 @@ ruma_api! {
error: crate::Error 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. /// Categories of events that can be searched for.
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Outgoing, Serialize)]
pub struct Categories { #[non_exhaustive]
/// Criteria for searching a category of events. pub struct Categories<'a> {
/// Criteria for searching room events.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub room_events: Option<Criteria>, pub room_events: Option<Criteria<'a>>,
}
impl<'a> Categories<'a> {
/// Creates an empty `Categories`.
pub fn new() -> Self {
Self { room_events: None }
}
} }
/// Criteria for searching a category of events. /// Criteria for searching a category of events.
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Outgoing, Serialize)]
pub struct Criteria { pub struct Criteria<'a> {
/// The string to search events for. /// The string to search events for.
pub search_term: String, pub search_term: &'a str,
/// The keys to search for. Defaults to all keys. /// The keys to search for. Defaults to all keys.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub keys: Option<Vec<SearchKeys>>, pub keys: Option<&'a [SearchKeys]>,
/// A `Filter` to apply to the search. /// A `Filter` to apply to the search.
#[serde(skip_serializing_if = "Option::is_none")] #[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. /// Requests that the server partitions the result set based on the provided list of keys.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub groupings: Option<Groupings>, pub groupings: Option<Groupings<'a>>,
} }
/// Configures whether any context for the events returned are included in the response. /// 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. /// Requests that the server partitions the result set based on the provided list of keys.
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Copy, Debug, Outgoing, Serialize)]
pub struct Groupings { pub struct Groupings<'a> {
/// List of groups to request. /// List of groups to request.
#[serde(default, skip_serializing_if = "Vec::is_empty")] #[serde(default, skip_serializing_if = "<[_]>::is_empty")]
pub group_by: Vec<Grouping>, pub group_by: &'a [Grouping],
} }
/// The keys to search for. /// The keys to search for.

View File

@ -16,12 +16,14 @@ ruma_api! {
requires_authentication: true, requires_authentication: true,
} }
#[non_exhaustive]
request: { request: {
/// The user to look up. /// The user to look up.
#[ruma_api(path)] #[ruma_api(path)]
pub user_id: UserId, pub user_id: &'a UserId,
} }
#[non_exhaustive]
response: { response: {
/// The Matrix user ID of the user. /// The Matrix user ID of the user.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
@ -35,6 +37,20 @@ ruma_api! {
error: crate::Error 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. /// Information about a user's device.
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct DeviceInfo { pub struct DeviceInfo {

View File

@ -64,7 +64,7 @@ ruma_api! {
} }
/// Identification information for the user. /// 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")] #[serde(from = "user_serde::IncomingUserInfo", into = "user_serde::UserInfo")]
pub enum UserInfo<'a> { pub enum UserInfo<'a> {
/// Either a fully qualified Matrix user ID, or just the localpart (as part of the 'identifier' /// 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. /// The authentication mechanism.
#[derive(Clone, Debug, PartialEq, Eq, Outgoing, Serialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Outgoing, Serialize)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum LoginInfo<'a> { pub enum LoginInfo<'a> {
/// A password is supplied to authenticate. /// A password is supplied to authenticate.

View File

@ -3,7 +3,7 @@
use std::{collections::BTreeMap, time::Duration}; use std::{collections::BTreeMap, time::Duration};
use js_int::UInt; use js_int::UInt;
use ruma_api::ruma_api; use ruma_api::{ruma_api, Outgoing};
use ruma_common::{presence::PresenceState, Raw}; use ruma_common::{presence::PresenceState, Raw};
use ruma_events::{ use ruma_events::{
presence::PresenceEvent, AnyBasicEvent, AnyStrippedStateEvent, AnySyncEphemeralRoomEvent, 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. /// A filter represented either as its full JSON definition or the ID of a saved filter.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[ruma_api(query)] #[ruma_api(query)]
pub filter: Option<Filter>, pub filter: Option<Filter<'a>>,
/// A point in time to continue a sync from. /// A point in time to continue a sync from.
/// ///
@ -36,7 +36,7 @@ ruma_api! {
/// request. /// request.
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[ruma_api(query)] #[ruma_api(query)]
pub since: Option<String>, pub since: Option<&'a str>,
/// Controls whether to include the full state for all rooms the user is a member of. /// 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")] #[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. /// 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)] #[allow(clippy::large_enum_variant)]
#[serde(untagged)] #[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 // 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 // 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 // setup, we implement it through custom serde logic for this specific enum variant rather than
@ -113,7 +113,7 @@ pub enum Filter {
FilterDefinition(FilterDefinition), FilterDefinition(FilterDefinition),
/// The ID of a filter saved on the server. /// The ID of a filter saved on the server.
FilterId(String), FilterId(&'a str),
} }
/// Updates to rooms. /// Updates to rooms.
@ -408,13 +408,13 @@ mod tests {
use matches::assert_matches; use matches::assert_matches;
use super::{Filter, PresenceState, Request, Timeline}; use super::{Filter, IncomingFilter, IncomingRequest, PresenceState, Request, Timeline};
#[test] #[test]
fn serialize_all_params() { fn serialize_all_params() {
let req: http::Request<Vec<u8>> = Request { let req: http::Request<Vec<u8>> = Request {
filter: Some(Filter::FilterId("66696p746572".into())), filter: Some(Filter::FilterId("66696p746572")),
since: Some("s72594_4483_1934".into()), since: Some("s72594_4483_1934"),
full_state: true, full_state: true,
set_presence: PresenceState::Offline, set_presence: PresenceState::Offline,
timeout: Some(Duration::from_millis(30000)), timeout: Some(Duration::from_millis(30000)),
@ -449,10 +449,10 @@ mod tests {
.build() .build()
.unwrap(); .unwrap();
let req: Request = let req: IncomingRequest =
http::Request::builder().uri(uri).body(Vec::<u8>::new()).unwrap().try_into().unwrap(); http::Request::builder().uri(uri).body(Vec::<u8>::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.since, Some("myts".into()));
assert_eq!(req.full_state, false); assert_eq!(req.full_state, false);
assert_eq!(req.set_presence, PresenceState::Offline); assert_eq!(req.set_presence, PresenceState::Offline);
@ -468,7 +468,7 @@ mod tests {
.build() .build()
.unwrap(); .unwrap();
let req: Request = let req: IncomingRequest =
http::Request::builder().uri(uri).body(Vec::<u8>::new()).unwrap().try_into().unwrap(); http::Request::builder().uri(uri).body(Vec::<u8>::new()).unwrap().try_into().unwrap();
assert_matches!(req.filter, None); assert_matches!(req.filter, None);
@ -491,10 +491,10 @@ mod tests {
.build() .build()
.unwrap(); .unwrap();
let req: Request = let req: IncomingRequest =
http::Request::builder().uri(uri).body(Vec::<u8>::new()).unwrap().try_into().unwrap(); http::Request::builder().uri(uri).body(Vec::<u8>::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.since, None);
assert_eq!(req.full_state, false); assert_eq!(req.full_state, false);
assert_eq!(req.set_presence, PresenceState::Online); assert_eq!(req.set_presence, PresenceState::Online);

View File

@ -319,24 +319,25 @@ where
/// If the since parameter is None, the first Item might take a significant time to arrive and /// 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 /// 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. /// the logged-in users account and are visible to them.
pub fn sync( pub fn sync<'a>(
&self, &self,
filter: Option<SyncFilter>, filter: Option<SyncFilter<'a>>,
since: Option<String>, since: Option<String>,
set_presence: ruma_common::presence::PresenceState, set_presence: ruma_common::presence::PresenceState,
timeout: Option<Duration>, timeout: Option<Duration>,
) -> impl Stream<Item = Result<SyncResponse, Error<ruma_client_api::Error>>> ) -> impl Stream<Item = Result<SyncResponse, Error<ruma_client_api::Error>>>
+ TryStream<Ok = SyncResponse, Error = Error<ruma_client_api::Error>> { + TryStream<Ok = SyncResponse, Error = Error<ruma_client_api::Error>>
+ 'a {
let client = self.clone(); let client = self.clone();
stream::try_unfold(since, move |since| { stream::try_unfold(since, move |since| {
let client = client.clone(); let client = client.clone();
let filter = filter.clone(); let filter = filter.clone(); // FIXME: Remove once `SyncFilter` is `Copy`
async move { async move {
let response = client let response = client
.request(SyncRequest { .request(SyncRequest {
filter, filter,
since, since: since.as_deref(),
full_state: false, full_state: false,
set_presence, set_presence,
timeout, timeout,