1use std::sync::Arc;
8
9use crate::DocId;
10use crate::structures::TERMINATED;
11
12pub const DOC_WINDOW_WORDS: usize = 64;
14pub const DOC_WINDOW_SIZE: u32 = DOC_WINDOW_WORDS as u32 * 64;
15pub type DocWindow = [u64; DOC_WINDOW_WORDS];
16
17pub const DOC_BATCH_SIZE: usize = 128;
19pub type DocBatch = [DocId; DOC_BATCH_SIZE];
20
21pub(super) fn fill_batch<D: DocSet + ?Sized>(cursor: &mut D, docs: &mut DocBatch) -> usize {
22 let mut count = 0;
23 let mut doc = cursor.doc();
24 while count < docs.len() && doc != TERMINATED {
25 docs[count] = doc;
26 count += 1;
27 doc = cursor.advance();
28 }
29 count
30}
31
32pub(super) fn retain_batch<D: DocSet + ?Sized>(
33 cursor: &mut D,
34 docs: &mut DocBatch,
35 len: usize,
36) -> usize {
37 assert!(len <= docs.len());
38 let mut kept = 0;
39 for i in 0..len {
40 let doc = docs[i];
41 if cursor.seek(doc) == doc {
42 docs[kept] = doc;
43 kept += 1;
44 }
45 }
46 kept
47}
48
49pub(super) fn fill_window<D: DocSet + ?Sized>(docs: &mut D, base: DocId, bits: &mut DocWindow) {
50 bits.fill(0);
51 let end = base.saturating_add(DOC_WINDOW_SIZE);
52 let mut doc = docs.seek(base);
53 while doc < end {
54 let offset = (doc - base) as usize;
55 bits[offset / 64] |= 1u64 << (offset % 64);
56 doc = docs.advance();
57 }
58}
59
60macro_rules! define_docset_trait {
63 ($($send_bounds:tt)*) => {
64 pub trait DocSet: $($send_bounds)* {
69 fn doc(&self) -> DocId;
71
72 fn advance(&mut self) -> DocId;
74
75 fn seek(&mut self, target: DocId) -> DocId {
77 let mut doc = self.doc();
78 while doc < target {
79 doc = self.advance();
80 }
81 doc
82 }
83
84 fn size_hint(&self) -> u32;
86
87 fn supports_doc_batches(&self) -> bool { false }
89
90 fn fill_doc_batch(&mut self, docs: &mut DocBatch) -> usize {
93 fill_batch(self, docs)
94 }
95
96 fn retain_doc_batch(&mut self, docs: &mut DocBatch, len: usize) -> usize {
99 retain_batch(self, docs, len)
100 }
101
102 fn supports_doc_windows(&self) -> bool { false }
104
105 fn fill_doc_window(&mut self, base: DocId, bits: &mut DocWindow) {
109 fill_window(self, base, bits);
110 }
111
112 }
113 };
114}
115
116#[cfg(not(target_arch = "wasm32"))]
117define_docset_trait!(Send + Sync);
118
119#[cfg(target_arch = "wasm32")]
120define_docset_trait!();
121
122pub(super) struct BitsetDocSet {
125 bits: super::DocBitset,
126 current: DocId,
127 count: u32,
128}
129
130impl BitsetDocSet {
131 pub(super) fn new(bits: super::DocBitset) -> Self {
132 let current = bits.next_set_bit(0).unwrap_or(TERMINATED);
133 let count = bits.count();
134 Self {
135 bits,
136 current,
137 count,
138 }
139 }
140}
141
142impl DocSet for BitsetDocSet {
143 fn doc(&self) -> DocId {
144 self.current
145 }
146
147 fn advance(&mut self) -> DocId {
148 self.seek(self.current.saturating_add(1))
149 }
150
151 fn seek(&mut self, target: DocId) -> DocId {
152 if target > self.current {
153 self.current = self.bits.next_set_bit(target).unwrap_or(TERMINATED);
154 }
155 self.current
156 }
157
158 fn size_hint(&self) -> u32 {
159 self.count
160 }
161
162 fn supports_doc_windows(&self) -> bool {
163 true
164 }
165
166 fn fill_doc_window(&mut self, base: DocId, window: &mut DocWindow) {
167 window.fill(0);
168 let end = base.saturating_add(DOC_WINDOW_SIZE);
169 let start = base.max(self.current);
170 if start >= end {
171 return;
172 }
173 let first = base as usize / 64;
174 let shift = base % 64;
175 for (offset, word) in window.iter_mut().enumerate() {
176 let index = first + offset;
177 *word = self.bits.bits.get(index).copied().unwrap_or(0) >> shift;
178 if shift != 0 {
179 *word |= self.bits.bits.get(index + 1).copied().unwrap_or(0) << (64 - shift);
180 }
181 }
182 let consumed = (start - base) as usize;
183 window[..consumed / 64].fill(0);
184 window[consumed / 64] &= u64::MAX << (consumed % 64);
185 self.current = self.bits.next_set_bit(end).unwrap_or(TERMINATED);
186 }
187}
188
189impl DocSet for Box<dyn DocSet + '_> {
192 fn supports_doc_batches(&self) -> bool {
193 (**self).supports_doc_batches()
194 }
195 fn fill_doc_batch(&mut self, docs: &mut DocBatch) -> usize {
196 (**self).fill_doc_batch(docs)
197 }
198 fn retain_doc_batch(&mut self, docs: &mut DocBatch, len: usize) -> usize {
199 (**self).retain_doc_batch(docs, len)
200 }
201 fn supports_doc_windows(&self) -> bool {
202 (**self).supports_doc_windows()
203 }
204 fn fill_doc_window(&mut self, base: DocId, bits: &mut DocWindow) {
205 (**self).fill_doc_window(base, bits);
206 }
207 #[inline]
208 fn doc(&self) -> DocId {
209 (**self).doc()
210 }
211 #[inline]
212 fn advance(&mut self) -> DocId {
213 (**self).advance()
214 }
215 #[inline]
216 fn seek(&mut self, target: DocId) -> DocId {
217 (**self).seek(target)
218 }
219 #[inline]
220 fn size_hint(&self) -> u32 {
221 (**self).size_hint()
222 }
223}
224
225pub struct SortedVecDocSet {
229 docs: Arc<Vec<u32>>,
230 pos: usize,
231}
232
233impl SortedVecDocSet {
234 pub fn new(docs: Arc<Vec<u32>>) -> Self {
235 Self { docs, pos: 0 }
236 }
237}
238
239impl DocSet for SortedVecDocSet {
240 #[inline]
241 fn doc(&self) -> DocId {
242 self.docs.get(self.pos).copied().unwrap_or(TERMINATED)
243 }
244
245 #[inline]
246 fn advance(&mut self) -> DocId {
247 if self.pos < self.docs.len() {
248 self.pos += 1;
249 }
250 self.doc()
251 }
252
253 fn seek(&mut self, target: DocId) -> DocId {
254 if self.pos >= self.docs.len() {
255 return TERMINATED;
256 }
257 let remaining = &self.docs[self.pos..];
258 match remaining.binary_search(&target) {
259 Ok(offset) => {
260 self.pos += offset;
261 self.docs[self.pos]
262 }
263 Err(offset) => {
264 self.pos += offset;
265 self.doc()
266 }
267 }
268 }
269
270 fn size_hint(&self) -> u32 {
271 self.docs.len().saturating_sub(self.pos) as u32
272 }
273
274 fn supports_doc_batches(&self) -> bool {
275 true
276 }
277
278 fn fill_doc_batch(&mut self, docs: &mut DocBatch) -> usize {
279 let count = (self.docs.len() - self.pos).min(docs.len());
280 docs[..count].copy_from_slice(&self.docs[self.pos..self.pos + count]);
281 self.pos += count;
282 count
283 }
284}
285
286pub struct IntersectionDocSet<A: DocSet, B: DocSet> {
290 a: A,
291 b: B,
292}
293
294impl<A: DocSet, B: DocSet> IntersectionDocSet<A, B> {
295 pub fn new(mut a: A, mut b: B) -> Self {
296 let mut da = a.doc();
298 let mut db = b.doc();
299 loop {
300 if da == TERMINATED || db == TERMINATED {
301 break;
302 }
303 if da == db {
304 break;
305 }
306 if da < db {
307 da = a.seek(db);
308 } else {
309 db = b.seek(da);
310 }
311 }
312 Self { a, b }
313 }
314}
315
316impl<A: DocSet, B: DocSet> DocSet for IntersectionDocSet<A, B> {
317 fn doc(&self) -> DocId {
318 let da = self.a.doc();
319 if da == TERMINATED || self.b.doc() == TERMINATED {
320 TERMINATED
321 } else {
322 da
323 }
324 }
325
326 fn advance(&mut self) -> DocId {
327 let mut da = self.a.advance();
328 let mut db = self.b.doc();
329 loop {
330 if da == TERMINATED || db == TERMINATED {
331 return TERMINATED;
332 }
333 if da == db {
334 return da;
335 }
336 if da < db {
337 da = self.a.seek(db);
338 } else {
339 db = self.b.seek(da);
340 }
341 }
342 }
343
344 fn seek(&mut self, target: DocId) -> DocId {
345 let mut da = self.a.seek(target);
346 let mut db = self.b.seek(target);
347 loop {
348 if da == TERMINATED || db == TERMINATED {
349 return TERMINATED;
350 }
351 if da == db {
352 return da;
353 }
354 if da < db {
355 da = self.a.seek(db);
356 } else {
357 db = self.b.seek(da);
358 }
359 }
360 }
361
362 fn size_hint(&self) -> u32 {
363 self.a.size_hint().min(self.b.size_hint())
364 }
365}
366
367pub struct AllDocSet {
371 current: u32,
372 num_docs: u32,
373}
374
375impl AllDocSet {
376 pub fn new(num_docs: u32) -> Self {
377 Self {
378 current: 0,
379 num_docs,
380 }
381 }
382}
383
384impl DocSet for AllDocSet {
385 #[inline]
386 fn doc(&self) -> DocId {
387 if self.current >= self.num_docs {
388 TERMINATED
389 } else {
390 self.current
391 }
392 }
393
394 #[inline]
395 fn advance(&mut self) -> DocId {
396 if self.current < self.num_docs {
397 self.current += 1;
398 }
399 self.doc()
400 }
401
402 #[inline]
403 fn seek(&mut self, target: DocId) -> DocId {
404 self.current = self.current.max(target);
405 self.doc()
406 }
407
408 fn size_hint(&self) -> u32 {
409 self.num_docs.saturating_sub(self.current)
410 }
411}
412
413pub struct EmptyDocSet;
417
418impl DocSet for EmptyDocSet {
419 #[inline]
420 fn doc(&self) -> DocId {
421 TERMINATED
422 }
423 #[inline]
424 fn advance(&mut self) -> DocId {
425 TERMINATED
426 }
427 #[inline]
428 fn seek(&mut self, _target: DocId) -> DocId {
429 TERMINATED
430 }
431 fn size_hint(&self) -> u32 {
432 0
433 }
434}
435
436pub struct PredicatedScorer<'a> {
447 driver: Box<dyn super::Scorer + 'a>,
449 predicates: Vec<super::DocPredicate<'a>>,
451 must_verifiers: Vec<Box<dyn super::Scorer + 'a>>,
453 must_not_verifiers: Vec<Box<dyn super::Scorer + 'a>>,
455}
456
457impl<'a> PredicatedScorer<'a> {
458 pub fn new(
459 driver: Box<dyn super::Scorer + 'a>,
460 predicates: Vec<super::DocPredicate<'a>>,
461 must_verifiers: Vec<Box<dyn super::Scorer + 'a>>,
462 must_not_verifiers: Vec<Box<dyn super::Scorer + 'a>>,
463 ) -> Self {
464 let mut s = Self {
465 driver,
466 predicates,
467 must_verifiers,
468 must_not_verifiers,
469 };
470 s.skip_non_matching();
472 s
473 }
474
475 #[inline]
477 fn check_filters(&mut self, doc: DocId) -> bool {
478 if !self.predicates.iter().all(|p| p(doc)) {
480 return false;
481 }
482 if !self.must_verifiers.iter_mut().all(|s| s.seek(doc) == doc) {
484 return false;
485 }
486 self.must_not_verifiers
488 .iter_mut()
489 .all(|s| s.seek(doc) != doc)
490 }
491
492 fn filter_window(
495 &mut self,
496 base: DocId,
497 bits: &mut DocWindow,
498 mut scores: Option<&mut [crate::Score; DOC_WINDOW_SIZE as usize]>,
499 ) {
500 for (word_index, word) in bits.iter_mut().enumerate() {
501 let mut remaining = *word;
502 while remaining != 0 {
503 let bit = remaining.trailing_zeros() as usize;
504 let offset = word_index * 64 + bit;
505 if self.check_filters(base + offset as u32) {
506 if let Some(scores) = scores.as_deref_mut() {
507 for verifier in &self.must_verifiers {
508 scores[offset] += verifier.score();
509 }
510 }
511 } else {
512 *word &= !(1u64 << bit);
513 }
514 remaining &= remaining - 1;
515 }
516 }
517 self.skip_non_matching();
518 }
519
520 fn skip_non_matching(&mut self) -> DocId {
522 let mut doc = self.driver.doc();
523 while doc != TERMINATED && !self.check_filters(doc) {
524 doc = self.driver.advance();
525 }
526 doc
527 }
528}
529
530impl DocSet for PredicatedScorer<'_> {
531 fn supports_doc_windows(&self) -> bool {
532 self.driver.supports_filtered_windows() && self.driver.supports_doc_windows()
533 }
534
535 fn fill_doc_window(&mut self, base: DocId, bits: &mut DocWindow) {
536 self.driver.fill_doc_window(base, bits);
537 self.filter_window(base, bits, None);
538 }
539
540 fn doc(&self) -> DocId {
541 self.driver.doc()
542 }
543
544 fn advance(&mut self) -> DocId {
545 self.driver.advance();
546 self.skip_non_matching()
547 }
548
549 fn seek(&mut self, target: DocId) -> DocId {
550 self.driver.seek(target);
551 self.skip_non_matching()
552 }
553
554 fn size_hint(&self) -> u32 {
555 self.driver.size_hint()
556 }
557}
558
559impl super::Scorer for PredicatedScorer<'_> {
560 fn supports_filtered_windows(&self) -> bool {
561 self.driver.supports_filtered_windows()
562 }
563
564 fn supports_score_windows(&self) -> bool {
565 self.driver.supports_filtered_windows() && self.driver.supports_score_windows()
566 }
567
568 fn fill_score_window(
569 &mut self,
570 base: DocId,
571 scores: &mut [crate::Score; DOC_WINDOW_SIZE as usize],
572 bits: &mut DocWindow,
573 ) {
574 self.driver.fill_score_window(base, scores, bits);
575 self.filter_window(base, bits, Some(scores));
576 }
577
578 fn score(&self) -> crate::Score {
579 let mut total = self.driver.score();
580 for v in &self.must_verifiers {
581 total += v.score();
582 }
583 total
584 }
585
586 fn matched_positions(&self) -> Option<super::MatchedPositions> {
587 let mut all: super::MatchedPositions = Vec::new();
588 if let Some(p) = self.driver.matched_positions() {
589 all.extend(p);
590 }
591 for v in &self.must_verifiers {
592 if let Some(p) = v.matched_positions() {
593 all.extend(p);
594 }
595 }
596 if all.is_empty() { None } else { Some(all) }
597 }
598}
599
600#[cfg(test)]
603mod tests {
604 use super::*;
605
606 #[test]
607 fn bitmap_windows_preserve_unaligned_bases_consumed_prefixes_and_tail_seeks() {
608 for stride in [1, 2, 63, 127] {
609 let expected: Vec<u32> = (0..12291).step_by(stride).collect();
610 let mut bits = super::super::DocBitset::new(12291);
611 for &doc in &expected {
612 bits.set(doc);
613 }
614 for base in [
615 0, 1, 63, 64, 4094, 4095, 4096, 8191, 10000, 12290, 12291, TERMINATED,
616 ] {
617 let mut cursor = BitsetDocSet::new(bits.clone());
618 cursor.seek(base.saturating_add(17));
619 let previous = cursor.doc();
620 let end = base.saturating_add(DOC_WINDOW_SIZE);
621 let mut actual = [u64::MAX; DOC_WINDOW_WORDS];
622 cursor.fill_doc_window(base, &mut actual);
623 let mut wanted = [0; DOC_WINDOW_WORDS];
624 for &doc in &expected {
625 if doc >= previous.max(base) && doc < end {
626 let relative = (doc - base) as usize;
627 wanted[relative / 64] |= 1 << (relative % 64);
628 }
629 }
630 assert_eq!(actual, wanted, "stride={stride}, base={base}");
631 assert_eq!(
632 cursor.doc(),
633 expected
634 .iter()
635 .copied()
636 .find(|&doc| doc >= previous.max(end))
637 .unwrap_or(TERMINATED)
638 );
639 }
640 let mut cursor = BitsetDocSet::new(bits);
641 let mut actual = Vec::new();
642 while cursor.doc() != TERMINATED {
643 let base = cursor.doc();
644 let mut words = [0; DOC_WINDOW_WORDS];
645 cursor.fill_doc_window(base, &mut words);
646 for (i, &word) in words.iter().enumerate() {
647 let mut word = word;
648 while word != 0 {
649 actual.push(base + i as u32 * 64 + word.trailing_zeros());
650 word &= word - 1;
651 }
652 }
653 }
654 assert_eq!(actual, expected);
655 assert_eq!(cursor.advance(), TERMINATED);
656 assert_eq!(cursor.seek(0), TERMINATED);
657 }
658 }
659
660 struct WindowScorer(SortedVecDocSet, f32, bool);
661
662 impl DocSet for WindowScorer {
663 fn doc(&self) -> DocId {
664 self.0.doc()
665 }
666 fn advance(&mut self) -> DocId {
667 self.0.advance()
668 }
669 fn seek(&mut self, target: DocId) -> DocId {
670 self.0.seek(target)
671 }
672 fn size_hint(&self) -> u32 {
673 self.0.size_hint()
674 }
675 fn supports_doc_windows(&self) -> bool {
676 true
677 }
678 }
679 impl crate::query::Scorer for WindowScorer {
680 fn supports_filtered_windows(&self) -> bool {
681 self.2
682 }
683 fn score(&self) -> f32 {
684 self.1 + (self.doc() % 7) as f32 * 0.125
685 }
686 fn supports_score_windows(&self) -> bool {
687 true
688 }
689 }
690
691 #[test]
692 fn filtering_keeps_leaf_windows_scalar_and_composite_windows_batched() {
693 use crate::query::Scorer;
694 for beneficial in [false, true] {
695 let driver = WindowScorer(
696 SortedVecDocSet::new(Arc::new(vec![1, 2, 3])),
697 1.0,
698 beneficial,
699 );
700 assert!(driver.supports_doc_windows() && driver.supports_score_windows());
701 let wrapped = PredicatedScorer::new(Box::new(driver), vec![], vec![], vec![]);
702 let wrapped = PredicatedScorer::new(Box::new(wrapped), vec![], vec![], vec![]);
703 assert_eq!(wrapped.supports_doc_windows(), beneficial);
704 assert_eq!(wrapped.supports_score_windows(), beneficial);
705 }
706 }
707
708 #[test]
709 fn filtered_windows_preserve_scores_membership_and_forward_cursor() {
710 use crate::query::Scorer;
711 let docs = Arc::new(vec![
712 0,
713 1,
714 2,
715 63,
716 64,
717 65,
718 4095,
719 4096,
720 4097,
721 8192,
722 8193,
723 u32::MAX - 2,
724 u32::MAX - 1,
725 ]);
726 let make = |required| {
727 let scorer = |docs, score| {
728 Box::new(WindowScorer(SortedVecDocSet::new(docs), score, true)) as Box<dyn Scorer>
729 };
730 PredicatedScorer::new(
731 scorer(docs.clone(), 0.1),
732 vec![Box::new(|doc| doc != 64 && doc != 8192)],
733 if required {
734 vec![
735 scorer(
736 Arc::new(docs.iter().copied().filter(|doc| *doc != 4096).collect()),
737 0.3,
738 ),
739 scorer(docs.clone(), 0.7),
740 ]
741 } else {
742 vec![]
743 },
744 vec![scorer(Arc::new(vec![1, 65, 4097]), 0.0)],
745 )
746 };
747 for required in [false, true] {
748 let mut scalar = make(required);
749 let mut expected = Vec::new();
750 while scalar.doc() != TERMINATED {
751 expected.push((scalar.doc(), scalar.score().to_bits()));
752 scalar.advance();
753 }
754 for scored in [false, true] {
755 let mut batched = make(required);
756 assert!(batched.supports_doc_windows());
757 assert!(batched.supports_score_windows());
758 let mut scores = [f32::NAN; DOC_WINDOW_SIZE as usize];
759 let mut bits = [u64::MAX; DOC_WINDOW_WORDS];
760 let mut actual = Vec::new();
761 for base in [0, 0, 4096, 8192, 12288, u32::MAX - 4096, TERMINATED] {
762 if scored {
763 batched.fill_score_window(base, &mut scores, &mut bits);
764 } else {
765 batched.fill_doc_window(base, &mut bits);
766 }
767 for (word, &mask) in bits.iter().enumerate() {
768 let mut mask = mask;
769 while mask != 0 {
770 let offset = word * 64 + mask.trailing_zeros() as usize;
771 let doc = base + offset as u32;
772 actual.push((doc, if scored { scores[offset].to_bits() } else { 0 }));
773 mask &= mask - 1;
774 }
775 }
776 let next = expected
777 .iter()
778 .find(|(doc, _)| *doc >= base.saturating_add(DOC_WINDOW_SIZE));
779 assert_eq!(batched.doc(), next.map_or(TERMINATED, |(doc, _)| *doc));
780 if let Some((_, score)) = next {
781 assert_eq!(batched.score().to_bits(), *score);
782 }
783 }
784 let expected: Vec<_> = expected
785 .iter()
786 .map(|&(doc, score)| (doc, if scored { score } else { 0 }))
787 .collect();
788 assert_eq!(actual, expected);
789 }
790 }
791 }
792
793 #[test]
794 fn test_sorted_vec_docset_basic() {
795 let docs = Arc::new(vec![1, 3, 5, 7, 9]);
796 let mut ds = SortedVecDocSet::new(docs);
797
798 assert_eq!(ds.doc(), 1);
799 assert_eq!(ds.advance(), 3);
800 assert_eq!(ds.advance(), 5);
801 assert_eq!(ds.seek(7), 7);
802 assert_eq!(ds.advance(), 9);
803 assert_eq!(ds.advance(), TERMINATED);
804 assert_eq!(ds.doc(), TERMINATED);
805 }
806
807 #[test]
808 fn test_sorted_vec_docset_seek_past() {
809 let docs = Arc::new(vec![1, 5, 10, 20]);
810 let mut ds = SortedVecDocSet::new(docs);
811
812 assert_eq!(ds.seek(3), 5);
813 assert_eq!(ds.seek(15), 20);
814 assert_eq!(ds.seek(21), TERMINATED);
815 }
816
817 #[test]
818 fn test_sorted_vec_docset_empty() {
819 let docs = Arc::new(vec![]);
820 let ds = SortedVecDocSet::new(docs);
821 assert_eq!(ds.doc(), TERMINATED);
822 }
823
824 #[test]
825 fn test_all_docset() {
826 let mut ds = AllDocSet::new(3);
827 assert_eq!(ds.doc(), 0);
828 assert_eq!(ds.advance(), 1);
829 assert_eq!(ds.advance(), 2);
830 assert_eq!(ds.advance(), TERMINATED);
831 }
832
833 #[test]
834 fn test_all_docset_seek() {
835 let mut ds = AllDocSet::new(10);
836 assert_eq!(ds.seek(5), 5);
837 assert_eq!(ds.seek(9), 9);
838 assert_eq!(ds.seek(10), TERMINATED);
839 }
840
841 #[test]
842 fn test_empty_docset() {
843 let mut ds = EmptyDocSet;
844 assert_eq!(ds.doc(), TERMINATED);
845 assert_eq!(ds.advance(), TERMINATED);
846 assert_eq!(ds.seek(5), TERMINATED);
847 assert_eq!(ds.size_hint(), 0);
848 }
849
850 #[test]
851 fn test_intersection_docset() {
852 let a = SortedVecDocSet::new(Arc::new(vec![1, 3, 5, 7, 9]));
853 let b = SortedVecDocSet::new(Arc::new(vec![2, 3, 5, 8, 9, 10]));
854 let mut isect = IntersectionDocSet::new(a, b);
855
856 assert_eq!(isect.doc(), 3);
857 assert_eq!(isect.advance(), 5);
858 assert_eq!(isect.advance(), 9);
859 assert_eq!(isect.advance(), TERMINATED);
860 }
861
862 #[test]
863 fn test_intersection_docset_empty() {
864 let a = SortedVecDocSet::new(Arc::new(vec![1, 3, 5]));
865 let b = SortedVecDocSet::new(Arc::new(vec![2, 4, 6]));
866 let isect = IntersectionDocSet::new(a, b);
867 assert_eq!(isect.doc(), TERMINATED);
868 }
869
870 #[test]
871 fn test_intersection_docset_seek() {
872 let a = SortedVecDocSet::new(Arc::new(vec![1, 5, 10, 20, 30]));
873 let b = SortedVecDocSet::new(Arc::new(vec![5, 10, 15, 20, 25, 30]));
874 let mut isect = IntersectionDocSet::new(a, b);
875
876 assert_eq!(isect.doc(), 5);
877 assert_eq!(isect.seek(15), 20);
878 assert_eq!(isect.advance(), 30);
879 assert_eq!(isect.advance(), TERMINATED);
880 }
881
882 #[test]
883 fn test_size_hint() {
884 let docs = Arc::new(vec![1, 2, 3, 4, 5]);
885 let mut ds = SortedVecDocSet::new(docs);
886 assert_eq!(ds.size_hint(), 5);
887 ds.advance();
888 assert_eq!(ds.size_hint(), 4);
889 ds.seek(4);
890 assert_eq!(ds.size_hint(), 2); }
892}