Skip to main content

ass_editor/utils/indexing/
fst.rs

1//! FST search index state and lightweight helpers.
2//!
3//! Holds the [`FstSearchIndex`] struct definition along with its constructor
4//! and search-scope filtering used by the
5//! [`DocumentSearch`](crate::utils::search::DocumentSearch) implementation.
6
7use super::common::IndexEntry;
8use crate::utils::search::SearchScope;
9
10use fst::Set;
11
12use std::{collections::HashMap, time::Instant};
13
14/// FST-based search index for high-performance queries
15#[cfg(feature = "search-index")]
16pub struct FstSearchIndex {
17    /// FST set for fast prefix/fuzzy matching
18    pub(super) fst_set: Option<Set<Vec<u8>>>,
19
20    /// Map from FST keys to document positions
21    pub(super) position_map: HashMap<String, Vec<IndexEntry>>,
22
23    /// Last known document content hash for cache invalidation
24    pub(super) content_hash: u64,
25
26    /// Index build timestamp for statistics
27    pub(super) build_time: Instant,
28
29    /// Index size in bytes
30    pub(super) index_size: usize,
31}
32
33#[cfg(feature = "search-index")]
34impl Default for FstSearchIndex {
35    fn default() -> Self {
36        Self::new()
37    }
38}
39
40#[cfg(feature = "search-index")]
41impl FstSearchIndex {
42    /// Create a new FST search index
43    pub fn new() -> Self {
44        Self {
45            fst_set: None,
46            position_map: HashMap::new(),
47            content_hash: 0,
48            build_time: {
49                #[cfg(feature = "std")]
50                {
51                    Instant::now()
52                }
53                #[cfg(not(feature = "std"))]
54                {
55                    0
56                }
57            },
58            index_size: 0,
59        }
60    }
61}
62
63#[cfg(feature = "search-index")]
64impl FstSearchIndex {
65    pub(super) fn matches_scope(&self, entry: &IndexEntry, scope: &SearchScope) -> bool {
66        match scope {
67            SearchScope::All => true,
68            SearchScope::Lines { start, end } => entry.line >= *start && entry.line <= *end,
69            SearchScope::Sections(sections) => {
70                if let Some(ref section) = entry.section_type {
71                    sections.contains(section)
72                } else {
73                    false
74                }
75            }
76            SearchScope::Range(range) => {
77                entry.position.offset >= range.start.offset
78                    && entry.position.offset <= range.end.offset
79            }
80        }
81    }
82}