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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
use core::fmt::Debug;
use core::marker::PhantomData;
use crate::ctx::Context;
use crate::ctx::Match;
use crate::err::Error;
use crate::regex::Regex;
pub trait NeuCond<'a, C>
where
C: Context<'a>,
{
fn check(&self, ctx: &C, item: &(usize, C::Item)) -> Result<bool, Error>;
}
pub trait Condition<'a, C>
where
C: Context<'a>,
{
type Out<F>;
fn set_cond<F>(self, cond: F) -> Self::Out<F>
where
F: NeuCond<'a, C>;
}
///
/// # Check the condition when match.
///
/// ```
/// # use neure::prelude::*;
/// #
/// # fn main() -> color_eyre::Result<()> {
/// # color_eyre::install()?;
/// let str = neu::not(b'"')
/// .many1()
/// // avoid match escape sequence
/// .set_cond(|ctx: &BytesCtx, (item_offset, _item): &(usize, u8)| {
/// Ok(!ctx.orig_at(ctx.offset() + item_offset)?.starts_with(b"\\\""))
/// })
/// // match the escape sequence in another regex
/// .or(b"\\\"")
/// .repeat(1..)
/// .pat();
/// let mut ctx = BytesCtx::new(br#""Hello world from \"rust\"!""#);
///
/// assert_eq!(ctx.try_mat(&str.enclose(b"\"", b"\""))?, Span::new(0, 28));
/// Ok(())
/// # }
/// ```
impl<'a, C, F> NeuCond<'a, C> for F
where
C: Context<'a>,
F: Fn(&C, &(usize, <C as Context<'a>>::Item)) -> Result<bool, Error>,
{
#[inline(always)]
fn check(&self, ctx: &C, item: &(usize, C::Item)) -> Result<bool, Error> {
let ret = (self)(ctx, item);
crate::trace_retval!("Fn", "NeuCond", item, ret)
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EmptyCond;
impl<'a, C> NeuCond<'a, C> for EmptyCond
where
C: Context<'a>,
{
fn check(&self, _: &C, _item: &(usize, C::Item)) -> Result<bool, Error> {
Ok(true)
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RegexCond<'a, C, T> {
regex: T,
marker: PhantomData<(&'a (), C)>,
}
impl<C, T> Debug for RegexCond<'_, C, T>
where
T: Debug,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("RegexCond")
.field("regex", &self.regex)
.finish()
}
}
impl<C, T> Clone for RegexCond<'_, C, T>
where
T: Clone,
{
fn clone(&self) -> Self {
Self {
regex: self.regex.clone(),
marker: self.marker,
}
}
}
impl<C, T> Copy for RegexCond<'_, C, T> where T: Copy {}
impl<C, T> RegexCond<'_, C, T> {
pub const fn new(regex: T) -> Self {
Self {
regex,
marker: PhantomData,
}
}
}
impl<'a, C, T> NeuCond<'a, C> for RegexCond<'a, C, T>
where
T: Regex<C>,
C: Match<'a>,
{
#[inline(always)]
fn check(&self, ctx: &C, item: &(usize, <C as Context<'a>>::Item)) -> Result<bool, Error> {
let mut ctx = ctx.clone_at(ctx.offset() + item.0)?;
let ret = ctx.try_mat(&self.regex);
crate::trace_retval!("RegexCond", "NeuCond", item, ret.is_ok());
Ok(ret.is_ok())
}
}
///
/// Create a condition using in [`Condition`] base on regex.
///
/// # Example
///
///```
/// # use neure::prelude::*;
/// #
/// # fn main() -> color_eyre::Result<()> {
/// # color_eyre::install()?;
/// let escape = b'\\'.then(b'"');
/// let str = neu::not(b'"')
/// .many1()
/// // avoid match escape sequence
/// .set_cond(neu::regex_cond(regex::not(escape)))
/// // match the escape sequence in another regex
/// .or(escape)
/// .repeat(1..)
/// .pat();
/// let mut ctx = BytesCtx::new(br#""Hello world from \"rust\"!""#);
///
/// assert_eq!(ctx.try_mat(&str.enclose(b"\"", b"\""))?, Span::new(0, 28));
/// Ok(())
/// # }
/// ```
pub const fn regex_cond<'a, C, T>(regex: T) -> RegexCond<'a, C, T> {
RegexCond::new(regex)
}