pub struct InfiniteQueryResource<T, E = QueryError> { /* private fields */ }core only.Expand description
An infinite query resource that manages paginated data.
Inspired by TanStack Query’s useInfiniteQuery. Each “page” is a T —
typically a batch of items fetched from an API.
Pages are stored internally as Arc<T> so that last_page_arc
and first_page_arc can hand the fetcher a cheap
Arc::clone instead of cloning the full page data.
Implementations§
Source§impl<T, E> InfiniteQueryResource<T, E>
impl<T, E> InfiniteQueryResource<T, E>
Sourcepub fn pages(&self) -> &VecDeque<Arc<T>>
pub fn pages(&self) -> &VecDeque<Arc<T>>
All loaded pages, in order from first to last.
Pages are stored internally as Arc<T> (audit #5) so that fetchers can
receive a cheap Arc::clone via first_page_arc /
last_page_arc instead of copying the page data.
Most call sites only need a &T view — use first_page
/ last_page, or iterate with .iter().map(|a| a.as_ref()).
Note: When status() is Failure, previously loaded pages are still
present and valid — the failure applies only to the most recent page fetch.
Use is_page_data_valid to check whether the
current page data can be relied upon.
Sourcepub fn page_count(&self) -> usize
pub fn page_count(&self) -> usize
Number of loaded pages.
Sourcepub fn first_page(&self) -> Option<&T>
pub fn first_page(&self) -> Option<&T>
The first loaded page, if any (borrowed view).
Sourcepub fn first_page_arc(&self) -> Option<Arc<T>>
pub fn first_page_arc(&self) -> Option<Arc<T>>
Cheap Arc::clone of the first page, if any (audit #5).
Hand this to a fetch_previous_page fetcher instead of cloning the full
page data — only the refcount is bumped.
Sourcepub fn last_page_arc(&self) -> Option<Arc<T>>
pub fn last_page_arc(&self) -> Option<Arc<T>>
Cheap Arc::clone of the last page, if any (audit #5).
Hand this to a fetch_next_page fetcher instead of cloning the full
page data — only the refcount is bumped.
Sourcepub fn has_next_page(&self) -> bool
pub fn has_next_page(&self) -> bool
Whether there are more pages after the last loaded page.
Sourcepub fn has_previous_page(&self) -> bool
pub fn has_previous_page(&self) -> bool
Whether there are more pages before the first loaded page.
Sourcepub fn is_fetching_next_page(&self) -> bool
pub fn is_fetching_next_page(&self) -> bool
Whether a fetch_next_page request is in flight.
Sourcepub fn is_fetching_previous_page(&self) -> bool
pub fn is_fetching_previous_page(&self) -> bool
Whether a fetch_previous_page request is in flight.
Sourcepub fn direction(&self) -> FetchDirection
pub fn direction(&self) -> FetchDirection
The fetch direction mode for this query.
Audit 3: Controls the default assumptions for has_next_page and
has_previous_page after construction and after reset().
Sourcepub fn status(&self) -> QueryStatus
pub fn status(&self) -> QueryStatus
Current status.
Sourcepub fn is_loading(&self) -> bool
pub fn is_loading(&self) -> bool
Whether loading.
Sourcepub fn active_request_id(&self) -> Option<RequestId>
pub fn active_request_id(&self) -> Option<RequestId>
Active request id.
Sourcepub fn cache_policy(&self) -> CachePolicy
pub fn cache_policy(&self) -> CachePolicy
Cache policy.
Sourcepub fn request_policy(&self) -> RequestPolicy
pub fn request_policy(&self) -> RequestPolicy
Request policy.
Sourcepub fn set_cache_policy(&mut self, policy: CachePolicy)
pub fn set_cache_policy(&mut self, policy: CachePolicy)
Set the cache policy.
This allows policy updates on existing resources when the same key is reused with different policies (e.g., a different TTL).
Sourcepub fn set_request_policy(&mut self, policy: RequestPolicy)
pub fn set_request_policy(&mut self, policy: RequestPolicy)
Set the request policy.
This allows policy updates on existing resources when the same key is reused with different request behavior.
Sourcepub fn retry_policy(&self) -> &RetryPolicy
pub fn retry_policy(&self) -> &RetryPolicy
The retry policy for page fetches.
Sourcepub fn set_retry_policy(&mut self, policy: RetryPolicy)
pub fn set_retry_policy(&mut self, policy: RetryPolicy)
Set the retry policy.
Stored by use_infinite_query from [InfiniteQueryOptions::retry_policy]
so that fetch helpers can read it from the entity.
Sourcepub fn started_at_ms(&self) -> Option<u64>
pub fn started_at_ms(&self) -> Option<u64>
When the current request started (ms).
Sourcepub fn last_updated_at_ms(&self) -> Option<u64>
pub fn last_updated_at_ms(&self) -> Option<u64>
When data was last updated (ms).
Sourcepub fn cache_age_ms(&self, now_ms: u64) -> Option<u64>
pub fn cache_age_ms(&self, now_ms: u64) -> Option<u64>
Cache age in milliseconds (L6).
Mirrors QueryResource::cache_age_ms: returns None when there is
no recorded last_updated_at, and also None on clock skew
(now_ms before the recorded timestamp) via checked_sub. Used by
InfiniteQueryBucket::collect_diagnostics so the infinite diagnostic
matches the regular query’s cache_age_ms behavior (the previous
inline saturating_sub returned Some(0) on skew).
Sourcepub fn cache_hits(&self) -> u64
pub fn cache_hits(&self) -> u64
Total cache hits.
Sourcepub fn cancelled_count(&self) -> u64
pub fn cancelled_count(&self) -> u64
Total cancelled requests.
Sourcepub fn ignored_results(&self) -> u64
pub fn ignored_results(&self) -> u64
Total ignored results (completed requests whose ID no longer matched).
Incremented when complete_page_success or complete_page_failure
receives a stale request ID, i.e. the result was produced by a fetch
that was subsequently replaced by a newer one.
Sourcepub fn retry_count(&self) -> u32
pub fn retry_count(&self) -> u32
Number of retry attempts for the current page fetch.
Sourcepub fn increment_retry(&mut self)
pub fn increment_retry(&mut self)
Increment the retry counter.
Sourcepub fn mark_ignored_result(&mut self)
pub fn mark_ignored_result(&mut self)
Increment the ignored-results counter.
Mirrors QueryResource::mark_ignored_result so the client layer’s
bulk-cancel path can bump ignored_results for infinite queries the
same way it does for regular queries (M5 core half).
Sourcepub fn reset_retry_count(&mut self)
pub fn reset_retry_count(&mut self)
Reset the retry counter to zero.
Sourcepub fn is_page_data_valid(&self) -> bool
pub fn is_page_data_valid(&self) -> bool
Whether the currently loaded page data is valid.
Returns true when:
- Status is
Success(pages are up to date), or - Status is
LoadingWithDataorLoadingEmpty(pages from a previous successful fetch are still valid while a new page is being fetched).
Returns false when:
- Status is
Idle(no pages have been fetched yet), or - Status is
Cancelled(data was explicitly cleared).
Important: When status is Failure, this returns true if pages were
previously loaded. A Failure status means the last page fetch failed,
but all previously loaded pages remain valid. This is distinct from
QueryResource where Failure invalidates the single data slot.
Sourcepub fn signal(&self) -> Option<&QuerySignal>
pub fn signal(&self) -> Option<&QuerySignal>
Cancellation signal.
Source§impl<T, E> InfiniteQueryResource<T, E>
impl<T, E> InfiniteQueryResource<T, E>
Sourcepub fn begin_fetch_next(
&mut self,
sequencer: &mut RequestSequencer,
now_ms: u64,
) -> Option<RequestId>
pub fn begin_fetch_next( &mut self, sequencer: &mut RequestSequencer, now_ms: u64, ) -> Option<RequestId>
Begin fetching the next page.
v2 fix: Cancels the old signal before creating a new one.
Cross-direction replacement (audit 2): When RequestPolicy::LatestWins
is set and a begin_fetch_previous is currently active, calling this
method will replace the previous-page request with this next-page request.
The old signal is cancelled and the previous-page result will be silently
discarded by complete_page_success (which returns false for stale IDs).
This is intentional for LatestWins semantics — the most recent direction
wins. Callers should check is_fetching_next_page() / is_fetching_previous_page()
before completing if they need to detect direction changes.
Per-direction IgnoreWhileLoading semantics (audit #87): the guard
only applies within the same direction. Beginning a next-page fetch while
is_fetching_previous_page is active bypasses the IgnoreWhileLoading
guard and cancels/replaces the in-flight previous fetch — the reverse is
also true for begin_fetch_previous. See [begin_fetch_previous] for the
mirror case.
Sourcepub fn begin_fetch_previous(
&mut self,
sequencer: &mut RequestSequencer,
now_ms: u64,
) -> Option<RequestId>
pub fn begin_fetch_previous( &mut self, sequencer: &mut RequestSequencer, now_ms: u64, ) -> Option<RequestId>
Begin fetching the previous page.
v2 fix: Cancels the old signal before creating a new one.
Cross-direction replacement (audit 2): When RequestPolicy::LatestWins
is set and a begin_fetch_next is currently active, calling this
method will replace the next-page request with this previous-page request.
The old signal is cancelled and the next-page result will be silently
discarded by complete_page_success (which returns false for stale IDs).
This is intentional for LatestWins semantics — the most recent direction
wins. Callers should check is_fetching_next_page() / is_fetching_previous_page()
before completing if they need to detect direction changes.
Per-direction IgnoreWhileLoading semantics (audit #87): the guard
only applies within the same direction. Beginning a previous-page fetch
while is_fetching_next_page is active bypasses the IgnoreWhileLoading
guard and cancels/replaces the in-flight next fetch — and vice versa for
begin_fetch_next. This is intentional: a same-direction re-entrancy is
suppressed under IgnoreWhileLoading, but an opposite-direction fetch is
treated as a new request that supersedes the current one.
Sourcepub fn begin_fetch_next_with_id(
&mut self,
maybe_request_id: Option<RequestId>,
now_ms: u64,
) -> Option<RequestId>
pub fn begin_fetch_next_with_id( &mut self, maybe_request_id: Option<RequestId>, now_ms: u64, ) -> Option<RequestId>
Like [begin_fetch_next] but accepts an optional pre-generated RequestId
instead of a RequestSequencer.
When maybe_request_id is Some, uses that ID directly — this is the
preferred call when the bucket’s co-located sequencer has already
pre-allocated an ID via QueryClient::next_request_id_for_infinite_key.
When None, falls back to a transient RequestSequencer::new() for
compatibility (e.g., when no QueryClient is available).
Passing the pre-allocated ID through ensures the RequestId stored as
the resource’s active_request_id matches the one the bucket’s sequencer
already consumed, keeping the bucket’s monotonic counter consistent with
the resource’s active request.
Sourcepub fn begin_fetch_previous_with_id(
&mut self,
maybe_request_id: Option<RequestId>,
now_ms: u64,
) -> Option<RequestId>
pub fn begin_fetch_previous_with_id( &mut self, maybe_request_id: Option<RequestId>, now_ms: u64, ) -> Option<RequestId>
Like [begin_fetch_previous] but accepts an optional pre-generated
RequestId instead of a RequestSequencer.
When maybe_request_id is Some, uses that ID directly — this is the
preferred call when the bucket’s co-located sequencer has already
pre-allocated an ID via QueryClient::next_request_id_for_infinite_key.
When None, falls back to a transient RequestSequencer::new() for
compatibility (e.g., when no QueryClient is available).
Passing the pre-allocated ID through ensures the RequestId stored as
the resource’s active_request_id matches the one the bucket’s sequencer
already consumed, keeping the bucket’s monotonic counter consistent with
the resource’s active request.
Sourcepub fn accept_current_request(
&mut self,
request_id: RequestId,
) -> Option<RequestGuard>
pub fn accept_current_request( &mut self, request_id: RequestId, ) -> Option<RequestGuard>
Accept the current request for two-phase completion.
Returns a RequestGuard if the request is still active, or None
if it was replaced or cancelled. The guard is a capability token for
the two-phase protocol (validate then complete).
This mirrors [QueryResource::accept_current_request] for consistency.
Use this when you need to inspect or transform data between validation
and completion, or when integrating with frameworks that prefer explicit
acceptance.
Sourcepub fn complete_success_with_guard(
&mut self,
_guard: RequestGuard,
page: T,
has_more: bool,
is_next: bool,
now_ms: u64,
)
pub fn complete_success_with_guard( &mut self, _guard: RequestGuard, page: T, has_more: bool, is_next: bool, now_ms: u64, )
Complete a page fetch with success using a guard (two-phase protocol).
The guard proves that accept_current_request already validated the
request is current.
Audit 3: Uses VecDeque::push_back for append and VecDeque::push_front
for prepend — both O(1) amortized.
N27: Any pages evicted by enforce_max_pages_remove_* are silently
dropped here (their Arc<T> refcounts are decremented, no leak). This
differs from append_page/prepend_page, which return evicted pages.
Returning them would change this method’s signature, so the drop is
intentional and documented.
Sourcepub fn complete_failure_with_guard(&mut self, _guard: RequestGuard, error: E)
pub fn complete_failure_with_guard(&mut self, _guard: RequestGuard, error: E)
Complete a page fetch with failure using a guard (two-phase protocol).
The guard proves that accept_current_request already validated the
request is current.
Note: This does NOT clear previously loaded pages. A Failure status
means the last page fetch failed, but previously loaded pages remain
accessible via pages. Use
is_page_data_valid to check whether page
data can be relied upon.
Sourcepub fn complete_page_success(
&mut self,
request_id: RequestId,
page: T,
has_more: bool,
is_next: bool,
now_ms: u64,
) -> bool
pub fn complete_page_success( &mut self, request_id: RequestId, page: T, has_more: bool, is_next: bool, now_ms: u64, ) -> bool
Complete a page fetch with success.
Convenience method that accepts and completes in one call.
Audit 3: Uses VecDeque::push_back for append and VecDeque::push_front
for prepend — both O(1) amortized.
N27: Any pages evicted by enforce_max_pages_remove_* are silently
dropped (their Arc<T> refcounts are decremented, no leak); see
complete_success_with_guard for
the rationale.
Sourcepub fn complete_page_failure(&mut self, request_id: RequestId, error: E) -> bool
pub fn complete_page_failure(&mut self, request_id: RequestId, error: E) -> bool
Complete a page fetch with failure.
Convenience method that accepts and completes in one call.
Note: This does NOT clear previously loaded pages. The Failure status
applies to the most recent page fetch attempt only — previously loaded pages
remain accessible via pages() and are still valid. Use
is_page_data_valid() to check whether page
data can be relied upon.
Sourcepub fn is_current_request(&self, request_id: RequestId) -> bool
pub fn is_current_request(&self, request_id: RequestId) -> bool
Whether the given request id is the current active request.
Sourcepub fn reset(&mut self)
pub fn reset(&mut self)
Reset to idle, clearing everything.
Note (audit 2): max_pages is preserved across resets — if it was
changed via set_max_pages(), that value persists.
Audit 3: has_next_page and has_previous_page are reset according
to the current FetchDirection:
ForwardOnly:has_next_page = true,has_previous_page = falseBidirectional: both reset tofalse
If the resource was previously exhausted, the caller should set the flags again after reset if the direction-based defaults are incorrect.
Sourcepub fn invalidate(&mut self)
pub fn invalidate(&mut self)
Invalidate the cache (clear last-updated timestamp).
Source§impl<T, E> InfiniteQueryResource<T, E>
impl<T, E> InfiniteQueryResource<T, E>
Sourcepub fn set_has_next_page(&mut self, has_next: bool)
pub fn set_has_next_page(&mut self, has_next: bool)
Set whether more pages are available after the last loaded page.
Sourcepub fn set_has_previous_page(&mut self, has_prev: bool)
pub fn set_has_previous_page(&mut self, has_prev: bool)
Set whether more pages are available before the first loaded page.
Sourcepub fn set_direction(&mut self, direction: FetchDirection)
pub fn set_direction(&mut self, direction: FetchDirection)
Set the fetch direction mode.
This does not change the current has_next_page / has_previous_page
flags — it only affects what reset() restores them to.
Sourcepub fn set_max_pages(&mut self, max: Option<usize>) -> Vec<Arc<T>>
pub fn set_max_pages(&mut self, max: Option<usize>) -> Vec<Arc<T>>
Set the maximum number of pages to retain.
A value of Some(0) is treated as unbounded (None) to prevent
accidentally draining all pages. Callers that want no page retention
should use reset() instead.
Returns evicted pages (if any) as Arc<T> handles so the caller can log
or process them without cloning the page data (audit #5).
Sourcepub fn append_page(&mut self, page: T) -> Vec<Arc<T>>
pub fn append_page(&mut self, page: T) -> Vec<Arc<T>>
Append a page to the end.
Audit 3: Uses VecDeque::push_back — O(1) amortized.
Returns evicted pages (if any) as Arc<T> handles (audit #5).
Sourcepub fn prepend_page(&mut self, page: T) -> Vec<Arc<T>>
pub fn prepend_page(&mut self, page: T) -> Vec<Arc<T>>
Prepend a page to the beginning.
Audit 3: Uses VecDeque::push_front — O(1) amortized instead of
the previous Vec::insert(0, page) which was O(n).
Returns evicted pages (if any) as Arc<T> handles (audit #5).
Source§impl<T, E> InfiniteQueryResource<T, E>
impl<T, E> InfiniteQueryResource<T, E>
Sourcepub fn new(
key: impl Into<QueryKey>,
cache_policy: CachePolicy,
request_policy: RequestPolicy,
) -> Self
pub fn new( key: impl Into<QueryKey>, cache_policy: CachePolicy, request_policy: RequestPolicy, ) -> Self
Create a new infinite query resource.
v2: max_pages defaults to Some(50) to prevent unbounded memory growth.
Audit 3: Uses FetchDirection::ForwardOnly by default, meaning
has_next_page starts true. Use new_bidirectional
for queries that paginate in both directions.
Sourcepub fn new_bidirectional(
key: impl Into<QueryKey>,
cache_policy: CachePolicy,
request_policy: RequestPolicy,
) -> Self
pub fn new_bidirectional( key: impl Into<QueryKey>, cache_policy: CachePolicy, request_policy: RequestPolicy, ) -> Self
Create a new infinite query resource configured for bidirectional paging.
Both has_next_page and has_previous_page default to false. The
query will not attempt to fetch in either direction until the caller
explicitly enables it.
Trait Implementations§
Source§impl<T: Clone, E: Clone> Clone for InfiniteQueryResource<T, E>
impl<T: Clone, E: Clone> Clone for InfiniteQueryResource<T, E>
Source§fn clone(&self) -> InfiniteQueryResource<T, E>
fn clone(&self) -> InfiniteQueryResource<T, E>
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl<'de, T, E> Deserialize<'de> for InfiniteQueryResource<T, E>where
T: DeserializeOwned,
E: DeserializeOwned,
impl<'de, T, E> Deserialize<'de> for InfiniteQueryResource<T, E>where
T: DeserializeOwned,
E: DeserializeOwned,
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl<T: Eq, E: Eq> Eq for InfiniteQueryResource<T, E>
Source§impl<T: 'static, E: 'static> ObservableResource for InfiniteQueryResource<T, E>
Available on crate feature client only.
impl<T: 'static, E: 'static> ObservableResource for InfiniteQueryResource<T, E>
client only.type Status = QueryStatus
fn observable_status(&self) -> QueryStatus
Source§impl<T, E> Serialize for InfiniteQueryResource<T, E>
impl<T, E> Serialize for InfiniteQueryResource<T, E>
impl<T: PartialEq, E: PartialEq> StructuralPartialEq for InfiniteQueryResource<T, E>
Auto Trait Implementations§
impl<T, E> Freeze for InfiniteQueryResource<T, E>
impl<T, E> RefUnwindSafe for InfiniteQueryResource<T, E>
impl<T, E> Send for InfiniteQueryResource<T, E>
impl<T, E> Sync for InfiniteQueryResource<T, E>
impl<T, E> Unpin for InfiniteQueryResource<T, E>
impl<T, E> UnsafeUnpin for InfiniteQueryResource<T, E>
impl<T, E> UnwindSafe for InfiniteQueryResource<T, E>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more