grammers_client/types/
iter_buffer.rs

1// Copyright 2020 - developers of the `grammers` project.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use crate::Client;
10pub use grammers_mtsender::InvocationError;
11use std::collections::VecDeque;
12
13/// Common parts to all requests that are used for creating iterators.
14///
15/// End-users should obtain particular instances of this type via client methods.
16pub struct IterBuffer<R, T> {
17    pub(crate) client: Client,
18    pub(crate) limit: Option<usize>,
19    pub(crate) fetched: usize,
20    pub(crate) buffer: VecDeque<T>,
21    pub(crate) last_chunk: bool,
22    pub(crate) total: Option<usize>,
23    pub(crate) request: R,
24}
25
26impl<R, T> IterBuffer<R, T> {
27    /// Create a new `IterBuffer` instance from a handle, capacity and request.
28    pub(crate) fn from_request(client: &Client, capacity: usize, request: R) -> Self {
29        Self {
30            client: client.clone(),
31            limit: None,
32            fetched: 0,
33            buffer: VecDeque::with_capacity(capacity),
34            last_chunk: false,
35            total: None,
36            request,
37        }
38    }
39
40    /// Change how many items will be returned from the iterator.
41    ///
42    /// Using `limit` instead of `take` on the iterator is useful because outgoing requests can
43    /// ask for less items from the server to only fetch what's needed.
44    pub fn limit(mut self, n: usize) -> Self {
45        self.limit = Some(n);
46        self
47    }
48
49    /// Checks whether the limit has been reached and no more items should be fetched.
50    fn limit_reached(&self) -> bool {
51        if let Some(limit) = self.limit {
52            self.fetched >= limit
53        } else {
54            false
55        }
56    }
57
58    /// Return the next result item from the buffer unless more data needs to be fetched.
59    ///
60    /// Data does not need to be fetched if the limit is reached or the buffer is empty and the
61    /// last chunk was reached.
62    pub(crate) fn next_raw(&mut self) -> Option<Result<Option<T>, InvocationError>> {
63        if self.limit_reached() || (self.buffer.is_empty() && self.last_chunk) {
64            Some(Ok(None))
65        } else {
66            self.pop_item().map(|item| Ok(Some(item)))
67        }
68    }
69
70    /// Determines the new "limit" for the request, so that no unnecessary items are fetched from
71    /// the network.
72    pub(crate) fn determine_limit(&self, max: usize) -> i32 {
73        if let Some(limit) = self.limit {
74            if self.fetched < limit {
75                (limit - self.fetched).min(max) as i32
76            } else {
77                1 // 0 would cause Telegram to send a default amount and not actually 0
78            }
79        } else {
80            max as i32
81        }
82    }
83
84    /// Pop a buffered item from the queue, and increment the amount of items fetched (returned).
85    pub(crate) fn pop_item(&mut self) -> Option<T> {
86        if let Some(item) = self.buffer.pop_front() {
87            self.fetched += 1;
88            Some(item)
89        } else {
90            None
91        }
92    }
93}