1use super::{Coverage, CoverageError};
4use crate::pki::CheckedPath;
5use crate::source::{Location, Query, ScopeError, Snapshot};
6use crate::timestamp::{Purpose, Verified};
7use core::hash::Hash;
8use core::marker::PhantomData;
9use structured_asn1::memory::{HashWork, MapExecution, MemoryError, OwnedMap, OwnedVec, Work};
10use structured_pkix::{Certificate, crl::CertificateList, ocsp::BasicResponse};
11mod storage;
12#[cfg(test)]
13mod tests;
14use storage::Storage;
15
16#[derive(Clone, Copy, PartialEq, Eq, Hash)]
17pub(super) enum Kind {
18 Certificate,
19 Crl,
20 Basic,
21}
22
23#[derive(Clone, Copy, PartialEq, Eq, Hash)]
26pub struct ArtifactKey<'source> {
27 pub(super) kind: Kind,
28 pub(super) bytes: &'source [u8],
29}
30
31impl HashWork for ArtifactKey<'_> {
32 fn hash_work(&self) -> Result<u64, MemoryError> {
33 u64::try_from(self.bytes.len())
34 .map_err(|_| MemoryError::WorkExceeded)?
35 .checked_add(2)
36 .ok_or(MemoryError::WorkExceeded)
37 }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
43pub struct CarriedOrigin {
44 pub token: usize,
46 pub choice: usize,
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53pub enum ArtifactSource {
54 Material(usize),
56 TokenCertificate {
58 token: usize,
60 certificate: usize,
62 },
63 TokenRevocation(CarriedOrigin),
65}
66
67#[derive(Debug, Clone, Copy)]
70pub struct Occurrence<N, D, G, P> {
71 source: ArtifactSource,
72 location: Location<N, D, G>,
73 placement: P,
74 embedded_certificate: Option<usize>,
75}
76
77type OccurrenceItem<N, D, G, P> = Result<Occurrence<N, D, G, P>, IndexError<N>>;
79
80impl<N: Copy, D: Copy, G: Copy, P: Copy> Occurrence<N, D, G, P> {
81 #[must_use]
83 pub fn new(source: ArtifactSource, location: Location<N, D, G>, placement: P) -> Self {
84 Self {
85 source,
86 location,
87 placement,
88 embedded_certificate: None,
89 }
90 }
91 #[must_use]
94 pub fn source(&self) -> ArtifactSource {
95 self.source
96 }
97 #[must_use]
99 pub fn location(&self) -> Location<N, D, G> {
100 self.location
101 }
102 #[must_use]
104 pub fn placement(&self) -> P {
105 self.placement
106 }
107 #[must_use]
110 pub fn embedded_certificate(&self) -> Option<usize> {
111 self.embedded_certificate
112 }
113}
114
115struct Entry<N, D, G, P> {
116 value: Occurrence<N, D, G, P>,
117 next: Option<usize>,
118}
119
120#[derive(Hash, PartialEq, Eq)]
121struct Bucket {
122 kind: Kind,
123 hash: u64,
124}
125impl HashWork for Bucket {
126 fn hash_work(&self) -> Result<u64, MemoryError> {
127 Ok(2)
128 }
129}
130struct Class<'source> {
131 key: ArtifactKey<'source>,
132 producer: structured_pkix::algorithm::Producer<'source>,
133 head: usize,
134 tail: usize,
135 next: Option<usize>,
136}
137
138pub struct Index<'source, N, D, G, P, O, W: Work, I> {
148 snapshot: Snapshot<D, G>,
149 signature: N,
150 keys: Option<OwnedMap<Bucket, usize, W>>,
151 classes: Storage<Class<'source>, W>,
152 entries: Storage<Entry<N, D, G, P>, W>,
153 open: &'source [O],
154 issuer: PhantomData<I>,
155 refused: Option<IndexError<N>>,
156}
157
158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
160pub enum IndexError<N> {
161 Scope(ScopeError<N>),
163 Foreign {
165 signature: N,
167 },
168 Resource {
170 signature: N,
172 cause: MemoryError,
174 },
175}
176
177#[derive(Debug)]
179pub enum ProjectionError<N, E> {
180 Index(IndexError<N>),
182 Projection(E),
184}
185
186pub type Projection<'s, N, D, G, P, O, W, I, E> =
188 Result<Index<'s, N, D, G, P, O, W, I>, ProjectionError<N, E>>;
189
190#[derive(Debug, Clone, Copy)]
193pub enum ArtifactRef<'view, 'source> {
194 Certificate(&'view Certificate<'source>),
196 Crl(&'view CertificateList<'source>),
198 Ocsp(&'view BasicResponse<'source>),
203}
204
205impl<'source> ArtifactRef<'_, 'source> {
206 fn producer(self) -> structured_pkix::algorithm::Producer<'source> {
207 match self {
208 Self::Certificate(value) => value.signature_algorithm().execution_origin(),
209 Self::Crl(value) => value.signature_algorithm().execution_origin(),
210 Self::Ocsp(value) => value.signature_algorithm().execution_origin(),
211 }
212 }
213 #[must_use]
217 pub fn execution_in<'operation, W: Work>(
218 &self,
219 work: &'operation W,
220 ) -> structured_asn1::memory::Execution<'operation>
221 where
222 'source: 'operation,
223 {
224 match self {
225 Self::Certificate(value) => value.execution_in(work),
226 Self::Crl(value) => value.execution_in(work),
227 Self::Ocsp(value) => value.execution_in(work),
228 }
229 }
230
231 #[must_use]
233 pub fn identity(self) -> ArtifactKey<'source> {
234 match self {
235 Self::Certificate(value) => ArtifactKey {
236 kind: Kind::Certificate,
237 bytes: value.as_bytes(),
238 },
239 Self::Crl(value) => ArtifactKey {
240 kind: Kind::Crl,
241 bytes: value.as_bytes(),
242 },
243 Self::Ocsp(value) => ArtifactKey {
244 kind: Kind::Basic,
245 bytes: value.as_bytes(),
246 },
247 }
248 }
249}
250
251#[derive(Debug)]
253pub enum Archived<N, D, G, P> {
254 Missing,
256 Uncovered,
259 Present(Occurrence<N, D, G, P>),
261}
262
263#[derive(Debug, Clone, Copy, PartialEq, Eq)]
265pub enum PathCertificate {
266 Anchor,
269 Member(usize),
271}
272
273#[derive(Debug)]
275pub struct ArchivedCertificate<N, D, G, P> {
276 pub role: PathCertificate,
278 pub availability: Archived<N, D, G, P>,
280}
281
282pub struct PathCertificates<'path, 'document, N, D, G, P> {
286 path: &'path CheckedPath<'document>,
287 archive: Location<N, D, G>,
288 entries: OwnedVec<ArchivedCertificate<N, D, G, P>>,
289 all_covered: bool,
290}
291
292impl<'path, 'document, N: Copy, D: Copy, G: Copy, P>
293 PathCertificates<'path, 'document, N, D, G, P>
294{
295 #[must_use]
297 pub fn path(&self) -> &'path CheckedPath<'document> {
298 self.path
299 }
300 #[must_use]
302 pub fn archive(&self) -> Location<N, D, G> {
303 self.archive
304 }
305 #[must_use]
307 pub fn entries(&self) -> &[ArchivedCertificate<N, D, G, P>] {
308 &self.entries
309 }
310 #[must_use]
313 pub fn all_certificates_covered(&self) -> bool {
314 self.all_covered
315 }
316}
317
318#[derive(Debug, Clone, Copy, PartialEq, Eq)]
320pub enum ArchiveError<N> {
321 Index(IndexError<N>),
323 Coverage(CoverageError<N>),
325 NotArchive {
327 property: N,
329 },
330}
331
332impl<'source, N: Copy + Eq, D: Copy + Eq, G: Copy + Eq, P: Copy, O, W: Work, I>
333 Index<'source, N, D, G, P, O, W, I>
334{
335 pub fn new<Q: Query<Id = N, Document = D, Generation = G, Work = W>>(
341 _issuer: I,
342 signature: N,
343 open: &'source [O],
344 query: &Q,
345 ) -> Result<Self, IndexError<N>> {
346 query.admit(signature, 1).map_err(IndexError::Scope)?;
347 let execution = query.execution();
348 Ok(Self {
349 snapshot: query.snapshot(),
350 signature,
351 keys: Some(execution.map()),
352 classes: Storage::new(execution.vector()),
353 entries: Storage::new(execution.vector()),
354 open,
355 issuer: PhantomData,
356 refused: None,
357 })
358 }
359
360 pub fn insert<Q: Query<Id = N, Document = D, Generation = G, Work = W>>(
368 &mut self,
369 _issuer: I,
370 artifact: ArtifactRef<'_, 'source>,
371 occurrence: Occurrence<N, D, G, P>,
372 query: &Q,
373 ) -> Result<(), IndexError<N>> {
374 if occurrence.location.snapshot != self.snapshot || query.snapshot() != self.snapshot {
377 return Err(IndexError::Foreign {
378 signature: self.signature,
379 });
380 }
381 let result = self.insert_artifact(artifact, occurrence, query);
382 if let Err(cause) = result {
383 self.refused = Some(cause);
384 }
385 result
386 }
387
388 fn insert_artifact<Q: Query<Id = N, Document = D, Generation = G, Work = W>>(
389 &mut self,
390 artifact: ArtifactRef<'_, 'source>,
391 occurrence: Occurrence<N, D, G, P>,
392 query: &Q,
393 ) -> Result<(), IndexError<N>> {
394 self.admit(query)?;
395 self.insert_key(artifact.identity(), artifact.producer(), occurrence, query)?;
396 if let ArtifactRef::Ocsp(response) = artifact {
397 for certificate in 0..response.certificates().len() {
398 self.admit(query)?;
399 self.insert_key(
400 ArtifactKey {
401 kind: Kind::Certificate,
402 bytes: response.certificates()[certificate].as_bytes(),
403 },
404 response.certificates()[certificate]
405 .signature_algorithm()
406 .execution_origin(),
407 Occurrence {
408 embedded_certificate: Some(certificate),
409 ..occurrence
410 },
411 query,
412 )?;
413 }
414 }
415 Ok(())
416 }
417
418 #[must_use]
420 pub fn open(&self) -> &'source [O] {
421 self.open
422 }
423
424 pub fn into_projected<N2, D2, G2, P2, I2, Q, E>(
436 self,
437 _issuer: I2,
438 signature: N2,
439 query: &Q,
440 mut project: impl FnMut(
441 Occurrence<N, D, G, P>,
442 ) -> Result<(ArtifactSource, Location<N2, D2, G2>, P2), E>,
443 ) -> Projection<'source, N2, D2, G2, P2, O, Q::Work, I2, E>
444 where
445 N2: Copy + Eq,
446 D2: Copy + Eq,
447 G2: Copy + Eq,
448 P2: Copy,
449 Q: Query<Id = N2, Document = D2, Generation = G2>,
450 {
451 query
452 .admit(signature, 1)
453 .map_err(|cause| ProjectionError::Index(IndexError::Scope(cause)))?;
454 let execution = query.execution();
455 let Index {
456 keys,
457 classes,
458 entries,
459 open,
460 refused,
461 ..
462 } = self;
463 if refused.is_some() {
464 return Err(ProjectionError::Index(IndexError::Foreign { signature }));
465 }
466 let keys = keys
467 .expect("restored artifact map")
468 .into_owned()
469 .with_execution(execution)
470 .map_err(|_| ProjectionError::Index(IndexError::Foreign { signature }))?;
471 let classes = classes
472 .into_inner()
473 .into_owned()
474 .with_execution(execution)
475 .map_err(|_| ProjectionError::Index(IndexError::Foreign { signature }))?;
476 let mut projected = execution.vector();
477 projected
478 .try_reserve_exact(entries.len())
479 .map_err(|cause| ProjectionError::Index(IndexError::Resource { signature, cause }))?;
480 query
481 .admit(
482 signature,
483 u64::try_from(entries.len()).map_err(|_| {
484 ProjectionError::Index(IndexError::Resource {
485 signature,
486 cause: MemoryError::WorkExceeded,
487 })
488 })?,
489 )
490 .map_err(|cause| ProjectionError::Index(IndexError::Scope(cause)))?;
491 for entry in entries.into_inner() {
492 let (source, location, placement) =
493 project(entry.value).map_err(ProjectionError::Projection)?;
494 if location.snapshot != query.snapshot() {
495 return Err(ProjectionError::Index(IndexError::Foreign { signature }));
496 }
497 projected
498 .try_push(Entry {
499 value: Occurrence {
500 source,
501 location,
502 placement,
503 embedded_certificate: entry.value.embedded_certificate,
504 },
505 next: entry.next,
506 })
507 .map_err(|cause| {
508 ProjectionError::Index(IndexError::Resource { signature, cause })
509 })?;
510 }
511 Ok(Index {
512 snapshot: query.snapshot(),
513 signature,
514 keys: Some(keys),
515 classes: Storage::new(classes),
516 entries: Storage::new(projected),
517 open,
518 issuer: PhantomData,
519 refused: None,
520 })
521 }
522
523 pub fn all_occurrences<'view, 'query, Q>(
530 &'view self,
531 query: &'query Q,
532 ) -> Result<
533 impl Iterator<Item = OccurrenceItem<N, D, G, P>>
534 + use<'view, 'query, 'source, N, D, G, P, O, W, Q, I>,
535 IndexError<N>,
536 >
537 where
538 Q: Query<Id = N, Document = D, Generation = G>,
539 {
540 self.admit(query)?;
541 let mut next = if self.entries.is_empty() {
542 None
543 } else {
544 Some(0)
545 };
546 Ok(core::iter::from_fn(move || {
547 let ordinal = next.take()?;
548 if let Err(cause) = self.admit(query) {
549 return Some(Err(cause));
550 }
551 let value = self.entries[ordinal].value;
552 if ordinal + 1 < self.entries.len() {
553 next = Some(ordinal + 1);
554 }
555 Some(Ok(value))
556 }))
557 }
558
559 #[must_use]
561 pub fn signature(&self) -> N {
562 self.signature
563 }
564
565 #[must_use]
567 pub fn snapshot(&self) -> Snapshot<D, G> {
568 self.snapshot
569 }
570
571 pub fn certificate<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
574 &'view self,
575 value: &Certificate<'_>,
576 query: &'query Q,
577 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
578 self.find(ArtifactRef::Certificate(value), query)
579 }
580 pub fn crl<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
583 &'view self,
584 value: &CertificateList<'_>,
585 query: &'query Q,
586 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
587 self.find(ArtifactRef::Crl(value), query)
588 }
589 pub fn ocsp<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
592 &'view self,
593 value: &BasicResponse<'_>,
594 query: &'query Q,
595 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
596 self.find(ArtifactRef::Ocsp(value), query)
597 }
598
599 pub fn artifact<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
601 &'view self,
602 artifact: ArtifactRef<'_, '_>,
603 query: &'query Q,
604 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
605 self.find(artifact, query)
606 }
607
608 pub fn require_signature<Q: Query<Id = N, Document = D, Generation = G>>(
610 &self,
611 signature: N,
612 query: &Q,
613 ) -> Result<(), IndexError<N>> {
614 self.admit(query)?;
615 let same =
616 query
617 .equal(self.signature, signature)
618 .map_err(|cause| IndexError::Resource {
619 signature: self.signature,
620 cause,
621 })?;
622 if !same {
623 return Err(IndexError::Foreign { signature });
624 }
625 Ok(())
626 }
627
628 pub fn archived<Q: Query<Id = N, Document = D, Generation = G>, C: Work>(
640 &self,
641 artifact: ArtifactRef<'_, '_>,
642 coverage: &Coverage<N, D, G, C, I>,
643 evidence: &Verified<N, D, G, I>,
644 query: &Q,
645 ) -> Result<Archived<N, D, G, P>, ArchiveError<N>>
646 where
647 N: HashWork,
648 {
649 if evidence.purpose() != Purpose::Archive {
650 return Err(ArchiveError::NotArchive {
651 property: evidence.property(),
652 });
653 }
654 if evidence.token().snapshot != self.snapshot {
656 return Err(ArchiveError::Index(IndexError::Foreign {
657 signature: self.signature,
658 }));
659 }
660 self.require_signature(evidence.signature(), query)
661 .map_err(ArchiveError::Index)?;
662 coverage
663 .require_evidence(evidence, evidence.property(), query)
664 .map_err(ArchiveError::Coverage)?;
665 let copies = self.find(artifact, query).map_err(ArchiveError::Index)?;
666 let mut found = false;
667 for copy in copies {
668 let copy = copy.map_err(ArchiveError::Index)?;
669 found = true;
670 if coverage
673 .selects(copy.location.node, query)
674 .map_err(ArchiveError::Coverage)?
675 {
676 return Ok(Archived::Present(copy));
677 }
678 }
679 Ok(if found {
680 Archived::Uncovered
681 } else {
682 Archived::Missing
683 })
684 }
685
686 pub fn archived_path<'path, 'document, Q, C: Work>(
697 &self,
698 path: &'path CheckedPath<'document>,
699 coverage: &Coverage<N, D, G, C, I>,
700 evidence: &Verified<N, D, G, I>,
701 query: &Q,
702 ) -> Result<PathCertificates<'path, 'document, N, D, G, P>, ArchiveError<N>>
703 where
704 N: HashWork,
705 Q: Query<Id = N, Document = D, Generation = G>,
706 {
707 query
708 .admit(self.signature, 1)
709 .map_err(|cause| ArchiveError::Index(IndexError::Scope(cause)))?;
710 let mut entries = query.execution().vector();
711 let mut all_covered = true;
712 let mut record = |certificate, role| {
713 let availability = self.archived(
714 ArtifactRef::Certificate(certificate),
715 coverage,
716 evidence,
717 query,
718 )?;
719 if !matches!(availability, Archived::Present(_)) {
720 all_covered = false;
721 }
722 entries
723 .try_push(ArchivedCertificate { role, availability })
724 .map_err(|cause| {
725 ArchiveError::Index(IndexError::Resource {
726 signature: self.signature,
727 cause,
728 })
729 })
730 };
731 if let Some(certificate) = path.anchor().certificate() {
732 record(certificate, PathCertificate::Anchor)?;
733 }
734 for (ordinal, member) in path.members().iter().enumerate() {
735 self.admit(query).map_err(ArchiveError::Index)?;
736 record(member.certificate(), PathCertificate::Member(ordinal))?;
737 }
738 Ok(PathCertificates {
739 path,
740 archive: evidence.token(),
741 entries: entries.into_owned(),
742 all_covered,
743 })
744 }
745
746 pub fn admit<Q: Query<Id = N, Document = D, Generation = G>>(
748 &self,
749 query: &Q,
750 ) -> Result<(), IndexError<N>> {
751 if let Some(cause) = self.refused {
752 return Err(cause);
753 }
754 if self.snapshot != query.snapshot() {
755 return Err(IndexError::Foreign {
756 signature: self.signature,
757 });
758 }
759 query.admit(self.signature, 2).map_err(IndexError::Scope)
760 }
761
762 fn insert_key<Q: Query<Id = N, Document = D, Generation = G, Work = W>>(
763 &mut self,
764 key: ArtifactKey<'source>,
765 producer: structured_pkix::algorithm::Producer<'source>,
766 value: Occurrence<N, D, G, P>,
767 query: &Q,
768 ) -> Result<(), IndexError<N>> {
769 self.admit(query)?;
770 let signature = self.signature;
771 let resource = |cause| IndexError::Resource { signature, cause };
772 let storage = |cause| match cause {
773 storage::Error::Resource(cause) => resource(cause),
774 storage::Error::Foreign => IndexError::Foreign { signature },
775 };
776 let work = producer.execution_in(query.execution());
777 work.charge_work(1).map_err(resource)?;
778 let bucket = Bucket {
779 kind: key.kind,
780 hash: self
781 .keys
782 .as_ref()
783 .expect("restored artifact map")
784 .fingerprint(&key, &work)
785 .map_err(resource)?,
786 };
787 let previous = self.class(&bucket, key, producer, query)?;
788 if previous.is_some() {
791 work.charge_work(2).map_err(resource)?;
792 }
793 let next = self.entries.len();
794 self.entries
795 .scoped(work, |entries| {
796 entries.try_push(Entry { value, next: None })
797 })
798 .map_err(storage)?;
799 if let Some(ordinal) = previous {
800 let tail = self.classes[ordinal].tail;
801 self.entries[tail].next = Some(next);
802 self.classes[ordinal].tail = next;
803 } else {
804 let table = self.keys.as_ref().expect("restored artifact map");
805 let head = table.get(&bucket, &work).map_err(resource)?.copied();
806 let ordinal = self.classes.len();
807 self.classes
808 .scoped(work, |classes| {
809 classes.try_push(Class {
810 key,
811 producer,
812 head: next,
813 tail: next,
814 next: head,
815 })
816 })
817 .map_err(storage)?;
818 let original = self.keys.take().expect("restored artifact map");
819 let (mut table, previous) = match original.rebind(work) {
820 MapExecution::Changed { map, previous } => (map, previous),
821 MapExecution::Foreign { map, .. } => {
822 self.keys = Some(map);
823 return Err(IndexError::Foreign { signature });
824 }
825 };
826 let result = table.try_insert(bucket, ordinal);
827 self.keys = Some(match table.rebind(previous) {
828 MapExecution::Changed { map, .. } => map,
829 MapExecution::Foreign { .. } => {
830 unreachable!("restore uses the original table account")
831 }
832 });
833 result.map_err(resource)?;
834 }
835 Ok(())
836 }
837
838 fn class<Q: Query<Id = N, Document = D, Generation = G>>(
839 &self,
840 bucket: &Bucket,
841 key: ArtifactKey<'_>,
842 producer: structured_pkix::algorithm::Producer<'_>,
843 query: &Q,
844 ) -> Result<Option<usize>, IndexError<N>> {
845 let resource = |cause| IndexError::Resource {
846 signature: self.signature,
847 cause,
848 };
849 let work = producer.execution_in(query.execution());
850 let mut next = self
851 .keys
852 .as_ref()
853 .expect("restored artifact map")
854 .get(bucket, &work)
855 .map_err(resource)?
856 .copied();
857 while let Some(ordinal) = next {
858 self.admit(query)?;
859 let class = &self.classes[ordinal];
860 let original = class.producer.execution_in(query.execution());
861 original.charge_work(1).map_err(resource)?;
862 if key.kind == class.key.kind && key.bytes.len() == class.key.bytes.len() {
863 if core::ptr::eq(key.bytes, class.key.bytes) {
864 return Ok(Some(ordinal));
865 }
866 let length = u64::try_from(key.bytes.len())
867 .map_err(|_| resource(MemoryError::WorkExceeded))?;
868 work.charge_work(length).map_err(resource)?;
869 original.charge_work(length).map_err(resource)?;
870 if key.bytes == class.key.bytes {
871 return Ok(Some(ordinal));
872 }
873 }
874 next = class.next;
875 }
876 Ok(None)
877 }
878
879 fn find<'view, 'query, Q: Query<Id = N, Document = D, Generation = G>>(
880 &'view self,
881 artifact: ArtifactRef<'_, '_>,
882 query: &'query Q,
883 ) -> Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> {
884 self.admit(query)?;
885 query.admit(self.signature, 1).map_err(IndexError::Scope)?;
886 let work = artifact.execution_in(query.execution());
887 work.charge_work(1).map_err(|cause| IndexError::Resource {
890 signature: self.signature,
891 cause,
892 })?;
893 let key = artifact.identity();
894 let bucket = Bucket {
895 kind: key.kind,
896 hash: self
897 .keys
898 .as_ref()
899 .expect("restored artifact map")
900 .fingerprint(&key, &work)
901 .map_err(|cause| IndexError::Resource {
902 signature: self.signature,
903 cause,
904 })?,
905 };
906 let next = self
907 .class(&bucket, key, artifact.producer(), query)?
908 .map(|ordinal| self.classes[ordinal].head);
909 Ok(Occurrences {
910 index: self,
911 query,
912 next,
913 })
914 }
915}
916
917pub type Lookup<'view, 'query, 'source, N, D, G, P, O, W, Q, I> =
919 Result<Occurrences<'view, 'query, 'source, N, D, G, P, O, W, Q, I>, IndexError<N>>;
920
921pub struct Occurrences<'view, 'query, 'source, N, D, G, P, O, W: Work, Q, I> {
925 index: &'view Index<'source, N, D, G, P, O, W, I>,
926 query: &'query Q,
927 next: Option<usize>,
928}
929
930impl<N: Copy + Eq, D: Copy + Eq, G: Copy + Eq, P: Copy, O, W: Work, Q, I> Iterator
931 for Occurrences<'_, '_, '_, N, D, G, P, O, W, Q, I>
932where
933 Q: Query<Id = N, Document = D, Generation = G>,
934{
935 type Item = Result<Occurrence<N, D, G, P>, IndexError<N>>;
936 fn next(&mut self) -> Option<Self::Item> {
937 let next = self.next.take()?;
938 if let Err(error) = self.index.admit(self.query) {
939 return Some(Err(error));
940 }
941 let entry = &self.index.entries[next];
942 self.next = entry.next;
943 Some(Ok(entry.value))
944 }
945}
946
947impl<N: Copy + Eq, D: Copy + Eq, G: Copy + Eq, P: Copy, O, W: Work, Q, I> core::iter::FusedIterator
948 for Occurrences<'_, '_, '_, N, D, G, P, O, W, Q, I>
949where
950 Q: Query<Id = N, Document = D, Generation = G>,
951{
952}