matrix_sdk/paginators/mod.rs
1// Copyright 2025 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Stateful paginators to help with paginated APIs.
16
17mod room;
18pub mod thread;
19
20use std::sync::Arc;
21
22use matrix_sdk_base::deserialized_responses::TimelineEvent;
23pub use room::*;
24use ruma::OwnedEventId;
25
26/// Pagination token data, indicating in which state is the current pagination.
27#[derive(Clone, Debug, PartialEq)]
28pub enum PaginationToken {
29 /// We never had a pagination token, so we'll start back-paginating from the
30 /// end, or forward-paginating from the start.
31 None,
32 /// We paginated once before, and we received a prev/next batch token that
33 /// we may reuse for the next query.
34 HasMore(String),
35 /// We've hit one end of the timeline (either the start or the actual end),
36 /// so there's no need to continue paginating.
37 HitEnd,
38}
39
40impl PaginationToken {
41 /// Convert to the token string, if we have one.
42 pub fn into_token(self) -> Option<String> {
43 match self {
44 Self::HasMore(token) => Some(token),
45 Self::None | Self::HitEnd => None,
46 }
47 }
48}
49
50impl From<Option<String>> for PaginationToken {
51 fn from(token: Option<String>) -> Self {
52 match token {
53 Some(val) => Self::HasMore(val),
54 None => Self::None,
55 }
56 }
57}
58
59/// The result of a single event pagination.
60#[derive(Debug)]
61pub struct PaginationResult {
62 /// Events returned during this pagination.
63 ///
64 /// If this is the result of a backward pagination, then the events are in
65 /// reverse topological order.
66 ///
67 /// If this is the result of a forward pagination, then the events are in
68 /// topological order.
69 pub events: Vec<TimelineEvent>,
70
71 /// Did we hit *an* end of the timeline?
72 ///
73 /// If this is the result of a backward pagination, this means we hit the
74 /// *start* of the timeline.
75 ///
76 /// If this is the result of a forward pagination, this means we hit the
77 /// *end* of the timeline.
78 pub hit_end_of_timeline: bool,
79}
80
81/// An error that happened when using a [`Paginator`].
82#[derive(Clone, Debug, thiserror::Error)]
83pub enum PaginatorError {
84 /// The target event could not be found.
85 #[error("target event with id {0} could not be found")]
86 EventNotFound(OwnedEventId),
87
88 /// We're trying to manipulate the paginator in the wrong state.
89 #[error("expected paginator state {expected:?}, observed {actual:?}")]
90 InvalidPreviousState {
91 /// The state we were expecting to see.
92 expected: PaginatorState,
93 /// The actual state when doing the check.
94 actual: PaginatorState,
95 },
96
97 /// There was another SDK error while paginating.
98 #[error("an error happened while paginating: {0}")]
99 SdkError(#[from] Arc<crate::Error>),
100}