Skip to main content

uqa_storage/clustered_postings/
read_cursor.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! A forward cursor that may borrow a retained index instead of materializing its postings.
8
9use super::{DocId, PostingCursor, PostingScore, StorageBackendResult};
10use crate::read_control::StorageReadControl;
11use uqa_core::memory::MemoryReservation;
12
13/// A unique cursor owner whose box payload is reserved before allocation.
14pub struct BudgetedPostingReadCursor<'a> {
15    cursor: Box<dyn PostingReadCursor + 'a>,
16    // Drop the cursor and its internal buffers before returning this payload reservation.
17    _memory: MemoryReservation,
18}
19impl<'a> BudgetedPostingReadCursor<'a> {
20    pub fn new<T: PostingReadCursor + 'a>(
21        cursor: T,
22        control: &StorageReadControl,
23    ) -> StorageBackendResult<Self> {
24        control.check()?;
25        let memory = control.memory().reserve(size_of::<T>())?;
26        Ok(Self {
27            cursor: Box::new(cursor),
28            _memory: memory,
29        })
30    }
31}
32impl PostingReadCursor for BudgetedPostingReadCursor<'_> {
33    fn doc_freq(&self) -> u64 {
34        self.cursor.doc_freq()
35    }
36    fn current(&self) -> Option<PostingScore> {
37        self.cursor.current()
38    }
39    fn advance(&mut self) -> StorageBackendResult<Option<PostingScore>> {
40        self.cursor.advance()
41    }
42    fn advance_to(&mut self, target: DocId) -> StorageBackendResult<Option<PostingScore>> {
43        self.cursor.advance_to(target)
44    }
45}
46
47/// Read-only candidate traversal bounded by the lifetime of the retained index read.
48pub trait PostingReadCursor: Send {
49    fn doc_freq(&self) -> u64;
50    fn current(&self) -> Option<PostingScore>;
51    fn advance(&mut self) -> StorageBackendResult<Option<PostingScore>>;
52    fn advance_to(&mut self, target: DocId) -> StorageBackendResult<Option<PostingScore>>;
53}
54
55/// Adapt an owned provider cursor without changing its incremental read strategy.
56pub struct OwnedPostingReadCursor(pub Box<dyn PostingCursor>);
57
58impl PostingReadCursor for OwnedPostingReadCursor {
59    fn doc_freq(&self) -> u64 {
60        self.0.doc_freq()
61    }
62    fn current(&self) -> Option<PostingScore> {
63        self.0.current()
64    }
65    fn advance(&mut self) -> StorageBackendResult<Option<PostingScore>> {
66        self.0.advance()
67    }
68    fn advance_to(&mut self, target: DocId) -> StorageBackendResult<Option<PostingScore>> {
69        self.0.advance_to(target)
70    }
71}