Skip to main content

vyre_libs/scan/
direct_gpu.rs

1//! Direct packed-byte GPU literal scanner.
2//!
3//! This is the focused public entry point for the packed-haystack scanner
4//! implemented by [`GpuLiteralSet`]. Keeping this wrapper thin prevents a
5//! second scanner implementation from drifting out of conformance with the
6//! literal-set engine.
7
8use crate::scan::literal_set::GpuLiteralSet;
9use vyre::ir::Program;
10use vyre::VyreBackend;
11pub use vyre_foundation::match_result::Match;
12
13/// State for a pipelined direct-to-GPU scan.
14pub struct DirectGpuScanner {
15    literal_set: GpuLiteralSet,
16}
17
18impl DirectGpuScanner {
19    /// Compile a set of literal patterns into a direct GPU matcher.
20    #[must_use]
21    pub fn compile(patterns: &[&[u8]]) -> Self {
22        Self {
23            literal_set: GpuLiteralSet::compile(patterns),
24        }
25    }
26
27    /// Return the compiled packed-byte GPU program.
28    #[must_use]
29    pub fn program(&self) -> &Program {
30        &self.literal_set.program
31    }
32
33    /// Cache identity of the underlying literal set. Used by the
34    /// `MatchScan::cache_key` impl so DirectGpuScanner caches don't
35    /// fork from the literal-set caches.
36    #[must_use]
37    pub fn literal_set_cache_key(&self) -> String {
38        use crate::scan::MatchScan;
39        MatchScan::cache_key(&self.literal_set)
40    }
41
42    /// CPU oracle for parity and tests.
43    #[must_use]
44    pub fn reference_scan(&self, haystack: &[u8]) -> Vec<Match> {
45        self.literal_set.reference_scan(haystack)
46    }
47
48    /// Dispatch the direct packed-byte matcher through a concrete backend.
49    ///
50    /// # Errors
51    ///
52    /// Returns [`vyre::BackendError`] when the backend cannot dispatch or read
53    /// back the compiled matcher.
54    pub fn scan<B: VyreBackend + ?Sized>(
55        &self,
56        backend: &B,
57        haystack: &[u8],
58        max_matches: u32,
59    ) -> Result<Vec<Match>, vyre::BackendError> {
60        self.literal_set.scan(backend, haystack, max_matches)
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn direct_gpu_scanner_reuses_real_literal_set_program() {
70        let patterns: [&[u8]; 2] = [b"abc", b"bc"];
71        let scanner = DirectGpuScanner::compile(&patterns);
72        let literal_set = GpuLiteralSet::compile(&patterns);
73        assert_eq!(
74            scanner.reference_scan(b"zabc"),
75            vec![Match::new(0, 1, 4), Match::new(1, 2, 4)]
76        );
77        assert_eq!(
78            scanner.program().fingerprint(),
79            literal_set.program.fingerprint()
80        );
81        assert_eq!(
82            scanner.program().workgroup_size(),
83            literal_set.program.workgroup_size()
84        );
85        assert!(!scanner.program().entry().is_empty());
86    }
87}