bmatcher_core/
pattern.rs

1use alloc::borrow::Cow;
2use core::fmt::Debug;
3
4use crate::Atom;
5
6/// A binary pattern is a structure used in matching processes and consists of two main components:
7///
8/// 1. Atoms  
9///    A list of instructions or actions that define how the matcher should process the data at the current cursor.
10///    
11/// 2. Byte Sequence  
12///    A sequence of bytes that the atoms can reference to match against actual input data.
13pub trait BinaryPattern: Send + Sync + Debug {
14    /// Retrieves the list of atoms within this binary pattern.
15    ///
16    /// The atoms define the actions or matching logic for the pattern.
17    fn atoms(&self) -> &[Atom];
18
19    /// Retrieves the byte sequence referenced by the atoms.
20    ///
21    /// This sequence represents the actual data to be matched against.
22    fn byte_sequence(&self) -> &[u8];
23
24    /// Returns an upper bound for the length of the save stack.
25    ///
26    /// # Note
27    /// This is only an upper bound. The actual length used might be smaller.
28    fn save_len(&self) -> usize {
29        self.atoms()
30            .iter()
31            .filter(|atom| {
32                matches!(
33                    atom,
34                    Atom::Read(_) | Atom::SaveCursor | Atom::SaveConstant(_)
35                )
36            })
37            .count()
38    }
39
40    /// Returns an upper bound for the length of the cursor stack.
41    ///
42    /// # Note
43    /// This is only an upper bound. The actual length used might be smaller.
44    fn cursor_len(&self) -> usize {
45        self.atoms()
46            .iter()
47            .filter(|atom| matches!(atom, Atom::CursorPush))
48            .count()
49    }
50}
51
52/// A flexible implementation of the [`BinaryPattern`] interface supporting both borrowed and owned data.
53///
54/// This struct uses [`alloc::borrow::Cow`] for both the [`Atom`] array and the byte sequence,
55/// allowing it to either borrow data without allocation or own it when necessary.
56/// This design makes it suitable for both compile-time defined and runtime-parsed patterns.
57///
58/// # Example
59/// ```
60/// # use bmatcher_core::*;
61/// let atoms = &[Atom::ByteSequence { seq_start: 0x00, seq_end: 0x01 }];
62/// let bytes = &[0x90];
63///
64/// // Borrowed (no allocation)
65/// let borrowed = GenericBinaryPattern::new(atoms, bytes);
66///
67/// // Owned (allocating)
68/// let owned = GenericBinaryPattern::new(vec![Atom::ByteSequence { seq_start: 0x00, seq_end: 0x01 }], vec![0x90]);
69#[derive(Debug, Clone)]
70pub struct GenericBinaryPattern<'a> {
71    atoms: Cow<'a, [Atom]>,
72    byte_sequence: Cow<'a, [u8]>,
73}
74
75impl<'a> GenericBinaryPattern<'a> {
76    /// Creates a new [`GenericBinaryPattern`] from borrowed or owned data.
77    ///
78    /// This constructor accepts any type that can be converted into a [`Cow`],
79    /// such as slices or vectors.  
80    /// Borrowed inputs (`&[Atom]`, `&[u8]`) avoid allocation, while owned inputs
81    /// (`Vec<Atom>`, `Vec<u8>`) store the data internally.
82    pub fn new(atoms: impl Into<Cow<'a, [Atom]>>, byte_sequence: impl Into<Cow<'a, [u8]>>) -> Self {
83        Self {
84            atoms: atoms.into(),
85            byte_sequence: byte_sequence.into(),
86        }
87    }
88
89    /// Creates a borrowed [`GenericBinaryPattern`] from static references.
90    ///
91    /// This constructor is `const` and does not perform any heap allocation.
92    /// It is ideal for defining patterns that reference constant or static data.
93    pub const fn new_const(atoms: &'a [Atom], byte_sequence: &'a [u8]) -> Self {
94        Self {
95            atoms: Cow::Borrowed(atoms),
96            byte_sequence: Cow::Borrowed(byte_sequence),
97        }
98    }
99
100    /// Converts the pattern into an owned version with a `'static` lifetime.
101    ///
102    /// Any borrowed data is cloned into owned memory, ensuring that the returned
103    /// pattern no longer depends on the original lifetimes.  
104    /// This is useful when the pattern needs to outlive temporary references.
105    pub fn into_owned(self) -> GenericBinaryPattern<'static> {
106        GenericBinaryPattern {
107            atoms: self.atoms.into_owned().into(),
108            byte_sequence: self.byte_sequence.into_owned().into(),
109        }
110    }
111}
112
113impl BinaryPattern for GenericBinaryPattern<'_> {
114    fn atoms(&self) -> &[Atom] {
115        self.atoms.as_ref()
116    }
117
118    fn byte_sequence(&self) -> &[u8] {
119        self.byte_sequence.as_ref()
120    }
121}