use std::future::poll_fn;
use std::pin::Pin;
use std::task::Context;
use futures_util::Stream;
use super::runtime::block_on;
const MAX_COLLECT_PAGES: u32 = 1_000;
const COLLECT_PREALLOC_CAP: usize = 10_000;
pub(crate) struct BlockingIter<S> {
stream: Pin<Box<S>>,
}
impl<S> BlockingIter<S> {
pub(crate) fn new(stream: S) -> Self {
Self {
stream: Box::pin(stream),
}
}
pub(crate) fn stream(&self) -> &S {
self.stream.as_ref().get_ref()
}
}
impl<S: Stream> BlockingIter<S> {
pub(crate) fn try_next(&mut self) -> crate::error::Result<Option<S::Item>> {
let stream = &mut self.stream;
block_on(poll_fn(move |cx: &mut Context<'_>| {
stream.as_mut().poll_next(cx)
}))
}
}
impl<S: Stream> Iterator for BlockingIter<S> {
type Item = S::Item;
fn next(&mut self) -> Option<Self::Item> {
self.try_next().unwrap_or_default()
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, None)
}
}
pub(crate) async fn collect_all_pages<TRaw, TOut>(
first_page: crate::types::pagination::Page<TRaw, TOut>,
) -> crate::error::Result<Vec<TOut>>
where
TRaw: Clone + 'static,
TOut: 'static,
{
let cap = usize::try_from(first_page.total()).unwrap_or(usize::MAX);
let mut all = Vec::with_capacity(cap.min(COLLECT_PREALLOC_CAP));
let mut first_items = first_page.items();
all.append(&mut first_items);
let mut current = first_page;
let mut pages: u32 = 1;
loop {
if pages >= MAX_COLLECT_PAGES && current.has_next() {
return Err(crate::error::HonchoError::Configuration(format!(
"pagination exceeded {MAX_COLLECT_PAGES} pages; refusing to fetch more to enforce the loop safety cap"
)));
}
let Some(next) = current.next_page().await? else {
break;
};
pages += 1;
let mut next_items = next.items();
all.append(&mut next_items);
current = next;
}
Ok(all)
}
pub(crate) fn collect_pages<TRaw, TOut>(
first_page_fut: impl std::future::Future<
Output = crate::error::Result<crate::types::pagination::Page<TRaw, TOut>>,
>,
) -> crate::error::Result<Vec<TOut>>
where
TRaw: Clone + 'static,
TOut: 'static,
{
block_on(async {
let page = first_page_fut.await?;
collect_all_pages(page).await
})?
}