page_turner/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![doc = include_str!("doc/Main.md")]
3
4#[cfg(feature = "local")]
5#[cfg_attr(docsrs, doc(cfg(feature = "local")))]
6pub mod local;
7
8#[cfg(feature = "mt")]
9pub mod mt;
10
11#[cfg(feature = "mutable")]
12#[cfg_attr(docsrs, doc(cfg(feature = "mutable")))]
13pub use local::mutable;
14
15#[cfg(feature = "dynamic")]
16#[cfg_attr(docsrs, doc(cfg(feature = "dynamic")))]
17pub use mt::dynamic;
18
19// `mt` is enabled by default so prelude reexports the mt::prelude. Users will need to specify a
20// prelude module manually like `page_turner::local::prelude*` if they want to use other flavours
21// of page turner.
22#[cfg(feature = "mt")]
23#[doc = include_str!("doc/prelude")]
24pub mod prelude {
25    pub use crate::mt::prelude::*;
26}
27
28// `mt` is enabled by default so it's reexported into the root.
29#[cfg(feature = "mt")]
30pub use crate::mt::*;
31
32/// A struct that combines items queried for the current page and an optional request to query the
33/// next page. If `next_request` is `None` `PageTurner` stops querying pages.
34///
35/// [`TurnedPage::next`] and [`TurnedPage::last`] constructors can be used for convenience.
36pub struct TurnedPage<I, R> {
37    pub items: I,
38    pub next_request: Option<R>,
39}
40
41impl<I, R> TurnedPage<I, R> {
42    pub fn new(items: I, next_request: Option<R>) -> Self {
43        Self {
44            items,
45            next_request,
46        }
47    }
48
49    pub fn next(items: I, next_request: R) -> Self {
50        Self {
51            items,
52            next_request: Some(next_request),
53        }
54    }
55
56    pub fn last(items: I) -> Self {
57        Self {
58            items,
59            next_request: None,
60        }
61    }
62}
63
64/// If a request for the next page doesn't require any data from the response and can be made out
65/// of the request for the current page implement this trait to enable `pages_ahead`,
66/// `pages_ahead_unordered` families of methods that query pages concurrently.
67///
68/// # Caveats
69///
70/// - Ensure that page turner's `turn_page` returns [`TurnedPage::last`] at some point or that you
71/// always use [`Limit::Pages`] in `*pages_ahead*` methods, otherwise `*pages_ahead*` streams will
72/// always end with errors.
73///
74/// - Ensure that page turner's `turn_page` produces equivalent next requests that query the same
75/// data so that `*pages_ahead*` streams and `pages` stream yield the same results.
76pub trait RequestAhead {
77    fn next_request(&self) -> Self;
78}
79
80/// If you use `pages_ahead` or `pages_ahead_unordered` families of methods and you know in advance
81/// how many pages you need to query, specify [`Limit::Pages`] to prevent redundant querying past
82/// the last existing page from being executed.
83#[allow(dead_code)]
84#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
85pub enum Limit {
86    #[default]
87    None,
88    Pages(usize),
89}
90
91mod internal;
92
93#[cfg(test)]
94mod test_utils;