From 0e8eb4e568dd02c91af7127f596d727ebc20d7fe Mon Sep 17 00:00:00 2001 From: Paul Woolcock Date: Sun, 5 Aug 2018 11:03:48 -0400 Subject: [PATCH] Add `PageIter` to abstract over iterating over pages --- src/entities/mod.rs | 2 + src/entities/pageiter.rs | 94 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 src/entities/pageiter.rs diff --git a/src/entities/mod.rs b/src/entities/mod.rs index c82ae5a..e45057c 100644 --- a/src/entities/mod.rs +++ b/src/entities/mod.rs @@ -6,6 +6,7 @@ pub mod instance; pub mod list; pub mod mention; pub mod notification; +pub mod pageiter; pub mod relationship; pub mod report; pub mod search_result; @@ -27,6 +28,7 @@ pub mod prelude { pub use super::list::List; pub use super::mention::Mention; pub use super::notification::Notification; + pub use super::pageiter::PageIter; pub use super::relationship::Relationship; pub use super::report::Report; pub use super::search_result::SearchResult; diff --git a/src/entities/pageiter.rs b/src/entities/pageiter.rs new file mode 100644 index 0000000..52c92dc --- /dev/null +++ b/src/entities/pageiter.rs @@ -0,0 +1,94 @@ +use page::Page; +use entities::{ + account::Account, + notification::Notification, + relationship::Relationship, + report::Report, + status::{Emoji, Status} +}; +use serde::Deserialize; + +macro_rules! into_pageiter { + ($typ:ty) => { + impl<'a> IntoIterator for Page<'a, $typ> { + type Item = $typ; + type IntoIter = PageIter<'a, $typ>; + + fn into_iter(self) -> PageIter<'a, $typ> { + PageIter::new(self) + } + } + } +} + +into_pageiter!(Status); +into_pageiter!(Account); +into_pageiter!(String); +into_pageiter!(Emoji); +into_pageiter!(Notification); +into_pageiter!(Report); +into_pageiter!(Relationship); + +pub struct PageIter<'a, T: Clone + for<'de> Deserialize<'de>> { + page: Page<'a, T>, + buffer: Vec, + cur_idx: usize, + use_initial: bool, +} + +impl<'a, T: Clone + for<'de> Deserialize<'de>> PageIter<'a, T> { + fn new(page: Page<'a, T>) -> PageIter<'a, T> { + PageIter { + page: page, + buffer: vec![], + cur_idx: 0, + use_initial: true, + } + } + + fn need_next_page(&self) -> bool { + self.buffer.is_empty() || + self.cur_idx == self.buffer.len() + } + + fn fill_next_page(&mut self) -> Option<()> { + let items = if let Ok(items) = self.page.next_page() { + items + } else { + return None; + }; + if let Some(items) = items { + self.buffer = items; + self.cur_idx = 0; + Some(()) + } else { + None + } + } +} + +impl<'a, T: Clone+ for<'de> Deserialize<'de>> Iterator for PageIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + if self.use_initial { + let idx = self.cur_idx; + if self.cur_idx == self.page.initial_items.len() - 1 { + self.cur_idx = 0; + self.use_initial = false; + } else { + self.cur_idx += 1; + } + Some(self.page.initial_items[idx].clone()) + } else { + if self.need_next_page() { + if self.fill_next_page().is_none() { + return None; + } + } + let idx = self.cur_idx; + self.cur_idx += 1; + Some(self.buffer[idx].clone()) + } + } +}