1 | use core::mem::size_of; |
2 | |
3 | use crate::util::wire::{self, DeserializeError, Endian, SerializeError}; |
4 | |
5 | /// The kind of anchored starting configurations to support in a DFA. |
6 | /// |
7 | /// Fully compiled DFAs need to be explicitly configured as to which anchored |
8 | /// starting configurations to support. The reason for not just supporting |
9 | /// everything unconditionally is that it can use more resources (such as |
10 | /// memory and build time). The downside of this is that if you try to execute |
11 | /// a search using an [`Anchored`](crate::Anchored) mode that is not supported |
12 | /// by the DFA, then the search will return an error. |
13 | #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
14 | pub enum StartKind { |
15 | /// Support both anchored and unanchored searches. |
16 | Both, |
17 | /// Support only unanchored searches. Requesting an anchored search will |
18 | /// panic. |
19 | /// |
20 | /// Note that even if an unanchored search is requested, the pattern itself |
21 | /// may still be anchored. For example, `^abc` will only match `abc` at the |
22 | /// start of a haystack. This will remain true, even if the regex engine |
23 | /// only supported unanchored searches. |
24 | Unanchored, |
25 | /// Support only anchored searches. Requesting an unanchored search will |
26 | /// panic. |
27 | Anchored, |
28 | } |
29 | |
30 | impl StartKind { |
31 | pub(crate) fn from_bytes( |
32 | slice: &[u8], |
33 | ) -> Result<(StartKind, usize), DeserializeError> { |
34 | wire::check_slice_len(slice, size_of::<u32>(), "start kind bytes" )?; |
35 | let (n, nr) = wire::try_read_u32(slice, "start kind integer" )?; |
36 | match n { |
37 | 0 => Ok((StartKind::Both, nr)), |
38 | 1 => Ok((StartKind::Unanchored, nr)), |
39 | 2 => Ok((StartKind::Anchored, nr)), |
40 | _ => Err(DeserializeError::generic("unrecognized start kind" )), |
41 | } |
42 | } |
43 | |
44 | pub(crate) fn write_to<E: Endian>( |
45 | &self, |
46 | dst: &mut [u8], |
47 | ) -> Result<usize, SerializeError> { |
48 | let nwrite = self.write_to_len(); |
49 | if dst.len() < nwrite { |
50 | return Err(SerializeError::buffer_too_small("start kind" )); |
51 | } |
52 | let n = match *self { |
53 | StartKind::Both => 0, |
54 | StartKind::Unanchored => 1, |
55 | StartKind::Anchored => 2, |
56 | }; |
57 | E::write_u32(n, dst); |
58 | Ok(nwrite) |
59 | } |
60 | |
61 | pub(crate) fn write_to_len(&self) -> usize { |
62 | size_of::<u32>() |
63 | } |
64 | |
65 | #[cfg_attr (feature = "perf-inline" , inline(always))] |
66 | pub(crate) fn has_unanchored(&self) -> bool { |
67 | matches!(*self, StartKind::Both | StartKind::Unanchored) |
68 | } |
69 | |
70 | #[cfg_attr (feature = "perf-inline" , inline(always))] |
71 | pub(crate) fn has_anchored(&self) -> bool { |
72 | matches!(*self, StartKind::Both | StartKind::Anchored) |
73 | } |
74 | } |
75 | |