patterns/lib.rs
1//! # Pattern matching library
2//! Allows you to search for a pattern within data via an iterator interface.
3//! This library uses the core::simd abstraction and is fully no_std compatible.
4//!
5//! ## Usage
6//! ```
7//! use patterns::Pattern;
8//!
9//! let data = [0_u8; 1_000_00];
10//! // Allows . and ? as wildcard.
11//! // Any number of wildcard characters between spaces is considered a wildcard byte.
12//! let pattern: Pattern = "01 02 00 ? 59 ff".parse().unwrap();
13//! let mut iterator = pattern.matches(&data);
14//!
15//! for _found in iterator {
16//! // use _found
17//! }
18//! ```
19//!
20//! ## Limitations
21//! - The maximum amount of bytes supported inside a pattern are 64 bytes
22//! - Target alignment of the pattern to search for must be less or equal to 64
23//! - The pointer of data to search through must follow these invariants:
24//! - `data.as_ptr() - 64 > `[`usize::MIN`]
25//! - `data.as_ptr() + data.len() + 64 < `[`usize::MAX`]
26
27// todos
28// optimize pattern.len() <= alignment
29// explore getting rid of pattern.length
30
31#![feature(portable_simd)]
32#![no_std]
33// untested on big endian
34#![cfg(target_endian = "little")]
35
36pub use crate::{pattern::Pattern, scanner::Scanner};
37
38mod const_utils;
39mod masks;
40mod pattern;
41mod scanner;
42
43/// The type that holds a bit for each byte in [`BYTES`]
44pub type BytesMask = u64;
45
46const V128: usize = 16;
47const V256: usize = 32;
48const V512: usize = 64;
49const VUNKNOWN: usize = V512;
50
51/// Provides a constant optimizing `BYTES` (see [`Pattern`]) to target cpu simd
52/// width. This is a best-effort, defaulting to maximum supported bytes.
53///
54/// Note that `BYTES` also determines maximum pattern length.
55pub const OPTIMAL_BYTES: usize = default_vector_target_width();
56
57const fn default_vector_target_width() -> usize {
58 if (cfg!(target_arch = "arm") || cfg!(target_arch = "aarch64")) && cfg!(target_feature = "neon")
59 {
60 return V128;
61 }
62 if cfg!(target_arch = "hexagon") {
63 if cfg!(target_feature = "hvx-length128b") {
64 // 1024 bits
65 return V512;
66 }
67 if cfg!(target_feature = "hvx") {
68 return V512;
69 }
70 }
71 if cfg!(target_arch = "mips") && cfg!(target_feature = "msa") {
72 return V128;
73 }
74 if cfg!(target_arch = "powerpc")
75 && (cfg!(target_feature = "vsx") || cfg!(target_feature = "altivec"))
76 {
77 return V128;
78 }
79 if (cfg!(target_arch = "riscv32") || cfg!(target_arch = "riscv64"))
80 && cfg!(target_feature = "v")
81 {
82 return V128;
83 }
84 if (cfg!(target_arch = "wasm32") || cfg!(target_arch = "wasm64"))
85 && cfg!(target_feature = "simd128")
86 {
87 return V128;
88 }
89 if cfg!(target_arch = "x86") {
90 if cfg!(target_feature = "avx512f") {
91 return V512;
92 }
93 if cfg!(target_feature = "avx2") {
94 return V256;
95 }
96 if cfg!(target_feature = "sse2") {
97 return V128;
98 }
99 }
100 VUNKNOWN
101}