Skip to main content

InfiniteQueryResource

Struct InfiniteQueryResource 

Source
pub struct InfiniteQueryResource<T, E = QueryError> { /* private fields */ }
Available on crate feature 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>

Source

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.

Source

pub fn page_count(&self) -> usize

Number of loaded pages.

Source

pub fn first_page(&self) -> Option<&T>

The first loaded page, if any (borrowed view).

Source

pub fn last_page(&self) -> Option<&T>

The last loaded page, if any (borrowed view).

Source

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.

Source

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.

Source

pub fn has_next_page(&self) -> bool

Whether there are more pages after the last loaded page.

Source

pub fn has_previous_page(&self) -> bool

Whether there are more pages before the first loaded page.

Source

pub fn is_fetching_next_page(&self) -> bool

Whether a fetch_next_page request is in flight.

Source

pub fn is_fetching_previous_page(&self) -> bool

Whether a fetch_previous_page request is in flight.

Source

pub fn max_pages(&self) -> Option<usize>

Maximum number of pages to retain.

Source

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().

Source

pub fn status(&self) -> QueryStatus

Current status.

Source

pub fn error(&self) -> Option<&E>

Most recent error.

Source

pub fn is_loading(&self) -> bool

Whether loading.

Source

pub fn key(&self) -> &QueryKey

Cache key.

Source

pub fn active_request_id(&self) -> Option<RequestId>

Active request id.

Source

pub fn cache_policy(&self) -> CachePolicy

Cache policy.

Source

pub fn request_policy(&self) -> RequestPolicy

Request policy.

Source

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).

Source

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.

Source

pub fn retry_policy(&self) -> &RetryPolicy

The retry policy for page fetches.

Source

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.

Source

pub fn started_at_ms(&self) -> Option<u64>

When the current request started (ms).

Source

pub fn last_updated_at_ms(&self) -> Option<u64>

When data was last updated (ms).

Source

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).

Source

pub fn cache_hits(&self) -> u64

Total cache hits.

Source

pub fn cancelled_count(&self) -> u64

Total cancelled requests.

Source

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.

Source

pub fn retry_count(&self) -> u32

Number of retry attempts for the current page fetch.

Source

pub fn increment_retry(&mut self)

Increment the retry counter.

Source

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).

Source

pub fn reset_retry_count(&mut self)

Reset the retry counter to zero.

Source

pub fn has_data(&self) -> bool

Whether any pages have been loaded.

Source

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 LoadingWithData or LoadingEmpty (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.

Source

pub fn signal(&self) -> Option<&QuerySignal>

Cancellation signal.

Source§

impl<T, E> InfiniteQueryResource<T, E>

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn is_current_request(&self, request_id: RequestId) -> bool

Whether the given request id is the current active request.

Source

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 = false
  • Bidirectional: both reset to false

If the resource was previously exhausted, the caller should set the flags again after reset if the direction-based defaults are incorrect.

Source

pub fn invalidate(&mut self)

Invalidate the cache (clear last-updated timestamp).

Source§

impl<T, E> InfiniteQueryResource<T, E>

Source

pub fn set_has_next_page(&mut self, has_next: bool)

Set whether more pages are available after the last loaded page.

Source

pub fn set_has_previous_page(&mut self, has_prev: bool)

Set whether more pages are available before the first loaded page.

Source

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.

Source

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).

Source

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).

Source

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>

Source

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.

Source

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>

Source§

fn clone(&self) -> InfiniteQueryResource<T, E>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Debug, E: Debug> Debug for InfiniteQueryResource<T, E>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de, T, E> Deserialize<'de> for InfiniteQueryResource<T, E>

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

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.
Source§

impl<T: PartialEq, E: PartialEq> PartialEq for InfiniteQueryResource<T, E>

Source§

fn eq(&self, other: &InfiniteQueryResource<T, E>) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl<T, E> Serialize for InfiniteQueryResource<T, E>
where T: Serialize, E: Serialize,

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl<T: PartialEq, E: PartialEq> StructuralPartialEq for InfiniteQueryResource<T, E>

Auto Trait Implementations§

§

impl<T, E> Freeze for InfiniteQueryResource<T, E>
where VecDeque<Arc<T>>: Freeze, Option<E>: Freeze,

§

impl<T, E> RefUnwindSafe for InfiniteQueryResource<T, E>

§

impl<T, E> Send for InfiniteQueryResource<T, E>
where VecDeque<Arc<T>>: Send, Option<E>: Send,

§

impl<T, E> Sync for InfiniteQueryResource<T, E>
where VecDeque<Arc<T>>: Sync, Option<E>: Sync,

§

impl<T, E> Unpin for InfiniteQueryResource<T, E>
where VecDeque<Arc<T>>: Unpin, Option<E>: Unpin,

§

impl<T, E> UnsafeUnpin for InfiniteQueryResource<T, E>

§

impl<T, E> UnwindSafe for InfiniteQueryResource<T, E>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert 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>

Convert 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)

Convert &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)

Convert &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
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Serialize for T
where T: Serialize + ?Sized,

Source§

fn erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), Error>

Source§

fn do_erased_serialize( &self, serializer: &mut dyn Serializer, ) -> Result<(), ErrorImpl>

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more