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,
}
#[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<RoomEventFilter>,
}
#[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)
}

View File

@ -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 }
}
}

View File

@ -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 }
}
}

View File

@ -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<String>,
pub to: Option<&'a str>,
/// The direction to return events from.
#[ruma_api(query)]
@ -63,6 +63,7 @@ ruma_api! {
pub filter: Option<RoomEventFilter>,
}
#[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()),

View File

@ -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<String>,
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<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.
#[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<Vec<SearchKeys>>,
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<Groupings>,
pub groupings: Option<Groupings<'a>>,
}
/// 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<Grouping>,
#[serde(default, skip_serializing_if = "<[_]>::is_empty")]
pub group_by: &'a [Grouping],
}
/// The keys to search for.

View File

@ -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 {

View File

@ -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.

View File

@ -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<Filter>,
pub filter: Option<Filter<'a>>,
/// 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<String>,
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<Vec<u8>> = 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::<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.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::<u8>::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::<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.full_state, false);
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
/// 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<SyncFilter>,
filter: Option<SyncFilter<'a>>,
since: Option<String>,
set_presence: ruma_common::presence::PresenceState,
timeout: Option<Duration>,
) -> 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();
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,