bmatcher_core/
pattern.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use alloc::vec::Vec;
use core::fmt::Debug;

use crate::Atom;

/// A binary pattern is a structure used in matching processes and consists of two main components:
///
/// 1. Atoms  
///    A list of instructions or actions that define how the matcher should process the data at the current cursor.
///    
/// 2. Byte Sequence  
///    A sequence of bytes that the atoms can reference to match against actual input data.
pub trait BinaryPattern: Send + Sync + Debug {
    /// Retrieves the list of atoms within this binary pattern.
    ///
    /// The atoms define the actions or matching logic for the pattern.
    fn atoms(&self) -> &[Atom];

    /// Retrieves the byte sequence referenced by the atoms.
    ///
    /// This sequence represents the actual data to be matched against.
    fn byte_sequence(&self) -> &[u8];

    /// Returns an upper bound for the length of the save stack.
    ///
    /// # Note
    /// This is only an upper bound. The actual length used might be smaller.
    fn save_len(&self) -> usize {
        self.atoms()
            .iter()
            .filter(|atom| {
                matches!(
                    atom,
                    Atom::Read(_) | Atom::SaveCursor | Atom::SaveConstant(_)
                )
            })
            .count()
    }

    /// Returns an upper bound for the length of the cursor stack.
    ///
    /// # Note
    /// This is only an upper bound. The actual length used might be smaller.
    fn cursor_len(&self) -> usize {
        self.atoms()
            .iter()
            .filter(|atom| matches!(atom, Atom::CursorPush))
            .count()
    }
}

/// An implementation of the [BinaryPattern] interface that borrows the [Atom]s and byte sequence array.
///
/// This struct is primarily used alongside the [bmatcher_proc::pattern] macro to generate patterns at runtime.
#[derive(Debug, Clone, Copy)]
pub struct BorrowedBinaryPattern<'a> {
    atoms: &'a [Atom],
    byte_sequence: &'a [u8],
}

impl<'a> BorrowedBinaryPattern<'a> {
    pub const fn new(atoms: &'a [Atom], byte_sequence: &'a [u8]) -> Self {
        Self {
            atoms,
            byte_sequence,
        }
    }
}

impl BinaryPattern for BorrowedBinaryPattern<'_> {
    fn atoms(&self) -> &[Atom] {
        self.atoms
    }

    fn byte_sequence(&self) -> &[u8] {
        self.byte_sequence
    }
}

/// An implementation of the [BinaryPattern] interface that allocates a `Vec` for the [Atom]s and the byte sequence.
///
/// This struct is primarily used with [crate::compiler::parse_pattern] to parse binary patterns at runtime.
#[derive(Debug, Default)]
pub struct OwnedBinaryPattern {
    atoms: Vec<Atom>,
    byte_sequence: Vec<u8>,
}

impl OwnedBinaryPattern {
    pub fn new(atoms: Vec<Atom>, byte_sequence: Vec<u8>) -> Self {
        Self {
            byte_sequence,
            atoms,
        }
    }
}

impl BinaryPattern for OwnedBinaryPattern {
    fn byte_sequence(&self) -> &[u8] {
        &self.byte_sequence
    }

    fn atoms(&self) -> &[Atom] {
        &self.atoms
    }
}