Skip to main content

neure/
lib.rs

1#![doc = include_str!("../README.md")]
2#![no_std]
3pub mod ctor;
4pub mod ctx;
5pub mod err;
6pub mod iter;
7pub mod map;
8pub mod neu;
9pub mod regex;
10pub mod span;
11
12pub(crate) mod log;
13pub(crate) mod r#macro;
14pub(crate) use log::*;
15
16#[cfg(feature = "alloc")]
17pub(crate) mod alloc {
18    extern crate alloc;
19
20    pub use alloc::borrow::Cow;
21    pub use alloc::boxed::Box;
22    pub use alloc::rc::Rc;
23    pub use alloc::string::String;
24    pub use alloc::sync::Arc;
25    pub use alloc::vec;
26    pub use alloc::vec::Vec;
27}
28
29#[cfg(feature = "std")]
30pub(crate) mod std {
31    extern crate std;
32
33    #[allow(unused)]
34    pub use std::collections::BTreeSet;
35    #[allow(unused)]
36    pub use std::collections::HashSet;
37    pub use std::sync::Mutex;
38}
39
40#[cfg(any(feature = "log", feature = "tracing"))]
41pub trait MayDebug: core::fmt::Debug {}
42
43#[cfg(any(feature = "log", feature = "tracing"))]
44impl<T> MayDebug for T where T: core::fmt::Debug {}
45
46#[cfg(not(any(feature = "log", feature = "tracing")))]
47pub trait MayDebug {}
48
49#[cfg(not(any(feature = "log", feature = "tracing")))]
50impl<T> MayDebug for T {}
51
52pub use charize::charize;
53
54pub mod prelude {
55    pub use crate::ctor;
56    pub use crate::ctor::CtorIntoHelper;
57    pub use crate::ctor::CtorOps;
58    pub use crate::ctor::CtorRefAsDynCtor;
59    pub use crate::ctx::Assert;
60    pub use crate::ctx::BytesCtx;
61    pub use crate::ctx::CharsCtx;
62    pub use crate::ctx::Context;
63    pub use crate::ctx::Match;
64    pub use crate::ctx::MatchExt;
65    pub use crate::ctx::MatchMulti;
66    pub use crate::ctx::RegexCtx;
67    pub use crate::map;
68    pub use crate::neu;
69    pub use crate::neu::Condition;
70    pub use crate::neu::Neu;
71    pub use crate::neu::NeuCond;
72    pub use crate::neu::NeuIntoRegexOps;
73    pub use crate::neu::NeuOp;
74    pub use crate::regex;
75    pub use crate::regex::Regex;
76    pub use crate::regex::RegexIntoHelper;
77    pub use crate::regex::RegexRefAsCtor;
78    pub use crate::regex::RegexRefAsDynRegex;
79    pub use crate::span::ArrayStorer;
80    pub use crate::span::Span;
81    #[cfg(feature = "alloc")]
82    pub use crate::span::VecStorer;
83}
84
85#[cfg(test)]
86mod test {
87
88    use crate::prelude::*;
89    use crate::regex;
90
91    #[test]
92    fn test_all() {
93        assert!(test_space().is_ok());
94        assert!(test_char().is_ok());
95        assert!(test_chars().is_ok());
96        assert!(test_chars_negative().is_ok());
97        assert!(test_range().is_ok());
98        #[cfg(feature = "alloc")]
99        assert!(test_range_negative().is_ok());
100        #[cfg(feature = "alloc")]
101        assert!(test_other().is_ok());
102    }
103
104    macro_rules! test_t {
105        ($ctx:ident, $str:literal, $id:literal, $parser:expr) => {
106            let parser = $parser;
107
108            $ctx.reset_with($str);
109            assert!($ctx.try_mat(&parser).is_err());
110        };
111        ($ctx:ident, $str:literal, $id:literal, $parser:expr, $span:expr) => {
112            let parser = $parser;
113
114            $ctx.reset_with($str);
115            assert_eq!($span, $ctx.try_mat(&parser)?);
116        };
117    }
118
119    #[cfg(feature = "alloc")]
120    macro_rules! test_st {
121        ($ctx:ident, $storer:ident, $str:literal, $id:literal, $parser:expr) => {
122            let parser = $parser;
123
124            $ctx.reset_with($str);
125            $storer.reset();
126            assert!($storer.try_cap($id, &mut $ctx, &parser).is_err());
127        };
128        ($ctx:ident, $storer:ident, $str:literal, $id:literal, $parser:expr, $($span:expr)*) => {
129            let parser = $parser;
130            let spans = [$($span)*];
131
132            $ctx.reset_with($str);
133            $storer.reset();
134            $storer.try_cap($id, &mut $ctx, &parser)?;
135            for (i, span) in $storer.spans_iter($id).unwrap().enumerate() {
136                assert_eq!(span, spans[i]);
137            }
138        };
139    }
140
141    #[cfg(feature = "alloc")]
142    fn test_other() -> Result<(), crate::err::Error> {
143        let mut ctx = RegexCtx::new("");
144        let mut storer = VecStorer::new(1);
145
146        test_st!(ctx, storer, "abedf", 0, regex!(.), Span { beg: 0, len: 1 });
147        test_st!(ctx, storer, "abedf", 0, regex!(.?), Span { beg: 0, len: 1 });
148        test_st!(
149            ctx,
150            storer,
151            "\nabedf",
152            0,
153            regex!(.?),
154            Span { beg: 0, len: 0 }
155        );
156        test_st!(ctx, storer, "abedf", 0, regex!(.*), Span { beg: 0, len: 5 });
157        test_st!(
158            ctx,
159            storer,
160            "\nabedf",
161            0,
162            regex!(.*),
163            Span { beg: 0, len: 0 }
164        );
165        test_st!(ctx, storer, "abedf", 0, regex!(.+), Span { beg: 0, len: 5 });
166        test_st!(ctx, storer, "\nabedf", 0, regex!(.+));
167        test_st!(
168            ctx,
169            storer,
170            "abedf",
171            0,
172            regex!(.{2}),
173            Span { beg: 0, len: 2 }
174        );
175        test_st!(ctx, storer, "ab\nedf", 0, regex!(.{3}));
176        test_st!(
177            ctx,
178            storer,
179            "abedf",
180            0,
181            regex!(.{2,}),
182            Span { beg: 0, len: 5 }
183        );
184        test_st!(
185            ctx,
186            storer,
187            "abedf",
188            0,
189            regex!(.{4,6}),
190            Span { beg: 0, len: 5 }
191        );
192        test_st!(ctx, storer, "abe\ndf", 0, regex!(.{4,6}));
193        test_st!(
194            ctx,
195            storer,
196            "c\nabedf",
197            0,
198            regex!(^),
199            Span { beg: 0, len: 1 }
200        );
201
202        Ok(())
203    }
204
205    #[cfg(feature = "alloc")]
206    fn test_range_negative() -> Result<(), crate::err::Error> {
207        let mut ctx = RegexCtx::new("");
208        let mut storer = VecStorer::new(1);
209
210        test_st!(
211            ctx,
212            storer,
213            "Raefc",
214            0,
215            regex!([^a - z]),
216            Span { beg: 0, len: 1 }
217        );
218        test_st!(
219            ctx,
220            storer,
221            "你aefc",
222            0,
223            regex!([^a - z A - Z]),
224            Span { beg: 0, len: 3 }
225        );
226        test_st!(
227            ctx,
228            storer,
229            "aefc",
230            0,
231            regex!([^a - z]?),
232            Span { beg: 0, len: 0 }
233        );
234        test_st!(
235            ctx,
236            storer,
237            "AEUF",
238            0,
239            regex!([^a - z]?),
240            Span { beg: 0, len: 1 }
241        );
242        test_st!(
243            ctx,
244            storer,
245            "&AEUF",
246            0,
247            regex!([^a - z A - Z]),
248            Span { beg: 0, len: 1 }
249        );
250        test_st!(
251            ctx,
252            storer,
253            "AEUF",
254            0,
255            regex!([^a-z]*),
256            Span { beg: 0, len: 4 }
257        );
258        test_st!(
259            ctx,
260            storer,
261            "aefc",
262            0,
263            regex!([^a-z]*),
264            Span { beg: 0, len: 0 }
265        );
266        test_st!(
267            ctx,
268            storer,
269            "@#$%",
270            0,
271            regex!([^a - z A - Z]*),
272            Span { beg: 0, len: 4 }
273        );
274        test_st!(
275            ctx,
276            storer,
277            "AEUF",
278            0,
279            regex!([^a-z]+),
280            Span { beg: 0, len: 4 }
281        );
282        test_st!(ctx, storer, "aefc", 0, regex!([^a-z]+));
283        test_st!(
284            ctx,
285            storer,
286            "AEUF",
287            0,
288            regex!([^a-z]{3}),
289            Span { beg: 0, len: 3 }
290        );
291        test_st!(ctx, storer, "aefc", 0, regex!([^a-z]{3}));
292        test_st!(
293            ctx,
294            storer,
295            "AEUF",
296            0,
297            regex!([^a-z]{3,6}),
298            Span { beg: 0, len: 4 }
299        );
300        test_st!(ctx, storer, "aefc", 0, regex!([^a-z]{3,6}));
301        test_st!(
302            ctx,
303            storer,
304            "AEUF",
305            0,
306            regex!([^a-z]{3,}),
307            Span { beg: 0, len: 4 }
308        );
309        test_st!(ctx, storer, "aefc", 0, regex!([^a-z]{3,}));
310
311        test_st!(
312            ctx,
313            storer,
314            "@#$%",
315            0,
316            regex!([^'a' - 'z' 'A' - 'Z']*),
317            Span { beg: 0, len: 4 }
318        );
319        test_st!(
320            ctx,
321            storer,
322            "AEUF",
323            0,
324            regex!([^'a'-'z']+),
325            Span { beg: 0, len: 4 }
326        );
327        test_st!(ctx, storer, "aefc", 0, regex!([^'a'-'z']+));
328        test_st!(
329            ctx,
330            storer,
331            "AEUF",
332            0,
333            regex!([^'a'-'z']{3}),
334            Span { beg: 0, len: 3 }
335        );
336        test_st!(ctx, storer, "aefc", 0, regex!([^'a'-'z']{3}));
337        test_st!(
338            ctx,
339            storer,
340            "AEUF",
341            0,
342            regex!([^'a'-'z']{3,6}),
343            Span { beg: 0, len: 4 }
344        );
345        test_st!(ctx, storer, "aefc", 0, regex!([^'a'-'z']{3,6}));
346        test_st!(
347            ctx,
348            storer,
349            "AEUF",
350            0,
351            regex!([^'a'-'z']{3,}),
352            Span { beg: 0, len: 4 }
353        );
354        test_st!(ctx, storer, "aefc", 0, regex!([^'a'-'z']{3,}));
355        Ok(())
356    }
357
358    fn test_range() -> Result<(), crate::err::Error> {
359        let mut ctx = RegexCtx::new("");
360
361        test_t!(ctx, "aefc", 0, regex!([a - z]), Span { beg: 0, len: 1 });
362        test_t!(
363            ctx,
364            "aefc",
365            0,
366            regex!([a - z A - Z]),
367            Span { beg: 0, len: 1 }
368        );
369        test_t!(ctx, "aefc", 0, regex!([a - z]?), Span { beg: 0, len: 1 });
370        test_t!(ctx, "AEUF", 0, regex!([a - z]?), Span { beg: 0, len: 0 });
371        test_t!(
372            ctx,
373            "AEUF",
374            0,
375            regex!([a - z A - Z]),
376            Span { beg: 0, len: 1 }
377        );
378        test_t!(ctx, "aefc", 0, regex!([a-z]*), Span { beg: 0, len: 4 });
379        test_t!(ctx, "AEUF", 0, regex!([a-z]*), Span { beg: 0, len: 0 });
380        test_t!(
381            ctx,
382            "AEUF",
383            0,
384            regex!([a - z A - Z]*),
385            Span { beg: 0, len: 4 }
386        );
387        test_t!(ctx, "aefc", 0, regex!([a-z]+), Span { beg: 0, len: 4 });
388        test_t!(ctx, "AEUF", 0, regex!([a-z]+));
389        test_t!(ctx, "aefc", 0, regex!([a-z]{3}), Span { beg: 0, len: 3 });
390        test_t!(ctx, "AEUF", 0, regex!([a-z]{3}));
391        test_t!(ctx, "aefc", 0, regex!([a-z]{3,6}), Span { beg: 0, len: 4 });
392        test_t!(ctx, "AEUF", 0, regex!([a-z]{3,6}));
393        test_t!(ctx, "aefc", 0, regex!([a-z]{3,}), Span { beg: 0, len: 4 });
394        test_t!(ctx, "AEUF", 0, regex!([a-z]{3,}));
395
396        test_t!(ctx, "aefc", 0, regex!(['a' - 'z']), Span { beg: 0, len: 1 });
397        test_t!(
398            ctx,
399            "aefc",
400            0,
401            regex!(['a' - 'z']?),
402            Span { beg: 0, len: 1 }
403        );
404        test_t!(
405            ctx,
406            "AEUF",
407            0,
408            regex!(['a' - 'z']?),
409            Span { beg: 0, len: 0 }
410        );
411        test_t!(ctx, "aefc", 0, regex!(['a'-'z']*), Span { beg: 0, len: 4 });
412        test_t!(ctx, "AEUF", 0, regex!(['a'-'z']*), Span { beg: 0, len: 0 });
413        test_t!(ctx, "aefc", 0, regex!(['a'-'z']+), Span { beg: 0, len: 4 });
414        test_t!(ctx, "AEUF", 0, regex!(['a'-'z']+));
415        test_t!(
416            ctx,
417            "AEUF",
418            0,
419            regex!(['a'-'z''A'-'Z']+),
420            Span { beg: 0, len: 4 }
421        );
422        test_t!(
423            ctx,
424            "aefc",
425            0,
426            regex!(['a'-'z']{3}),
427            Span { beg: 0, len: 3 }
428        );
429        test_t!(ctx, "AEUF", 0, regex!(['a'-'z']{3}));
430        test_t!(
431            ctx,
432            "aefc",
433            0,
434            regex!(['a'-'z']{3,6}),
435            Span { beg: 0, len: 4 }
436        );
437        test_t!(ctx, "AEUF", 0, regex!(['a'-'z']{3,6}));
438        test_t!(
439            ctx,
440            "aefc",
441            0,
442            regex!(['a'-'z']{3,}),
443            Span { beg: 0, len: 4 }
444        );
445        test_t!(ctx, "AEUF", 0, regex!(['a'-'z']{3,}));
446
447        Ok(())
448    }
449
450    fn test_chars_negative() -> Result<(), crate::err::Error> {
451        let mut ctx = RegexCtx::new("");
452
453        test_t!(ctx, "aefc", 0, regex!([^b c d]), Span { beg: 0, len: 1 });
454        test_t!(ctx, "aefc", 0, regex!([^b c d]?), Span { beg: 0, len: 1 });
455        test_t!(
456            ctx,
457            "aefc",
458            0,
459            regex!([^'b' 'c' 'd']),
460            Span { beg: 0, len: 1 }
461        );
462        test_t!(
463            ctx,
464            "aefc",
465            0,
466            regex!([^'b' 'c' 'd']?),
467            Span { beg: 0, len: 1 }
468        );
469        test_t!(ctx, "daefc", 0, regex!([^b c d]?), Span { beg: 0, len: 0 });
470        test_t!(ctx, "aefc", 0, regex!([^b c d]*), Span { beg: 0, len: 3 });
471        test_t!(ctx, "daefc", 0, regex!([^b c d]*), Span { beg: 0, len: 0 });
472        test_t!(ctx, "aefc", 0, regex!([^b c d]+), Span { beg: 0, len: 3 });
473        test_t!(
474            ctx,
475            "aefcddd",
476            0,
477            regex!([^b c d]+),
478            Span { beg: 0, len: 3 }
479        );
480        test_t!(ctx, "baefcddd", 0, regex!([^b c d]+));
481        test_t!(ctx, "aefh", 0, regex!([^b c d]{4}), Span { beg: 0, len: 4 });
482        test_t!(
483            ctx,
484            "aefhcc",
485            0,
486            regex!([^b c d]{4,}),
487            Span { beg: 0, len: 4 }
488        );
489        test_t!(
490            ctx,
491            "aefhccd",
492            0,
493            regex!([^b c d]{4,7}),
494            Span { beg: 0, len: 4 }
495        );
496        test_t!(ctx, "aecfhccd", 0, regex!([^b c d]{4,7}));
497        Ok(())
498    }
499
500    fn test_chars() -> Result<(), crate::err::Error> {
501        let mut ctx = RegexCtx::new("");
502
503        test_t!(ctx, "dabcd", 0, regex!([b c d]), Span { beg: 0, len: 1 });
504        test_t!(ctx, "dabcd", 0, regex!([b c d]?), Span { beg: 0, len: 1 });
505        test_t!(ctx, "edabcd", 0, regex!([b c d]?), Span { beg: 0, len: 0 });
506        test_t!(ctx, "dbcd", 0, regex!([b c d]*), Span { beg: 0, len: 4 });
507        test_t!(ctx, "aeuyf", 0, regex!([b c d]*), Span { beg: 0, len: 0 });
508        test_t!(ctx, "dabcd", 0, regex!([b c d]+), Span { beg: 0, len: 1 });
509        test_t!(ctx, "dbcdfff", 0, regex!([b c d]+), Span { beg: 0, len: 4 });
510        test_t!(ctx, "abcd", 0, regex!([b c d]+));
511        test_t!(ctx, "dbcd", 0, regex!([b c d]{4}), Span { beg: 0, len: 4 });
512        test_t!(
513            ctx,
514            "dbcdccc",
515            0,
516            regex!([b c d]{4,}),
517            Span { beg: 0, len: 7 }
518        );
519        test_t!(
520            ctx,
521            "dbcdbb",
522            0,
523            regex!([b c d]{4,7}),
524            Span { beg: 0, len: 6 }
525        );
526
527        test_t!(
528            ctx,
529            "dabcd",
530            0,
531            regex!(['b' 'c' 'd']),
532            Span { beg: 0, len: 1 }
533        );
534        test_t!(
535            ctx,
536            "dabcd",
537            0,
538            regex!(['b' 'c' 'd']?),
539            Span { beg: 0, len: 1 }
540        );
541        test_t!(
542            ctx,
543            "edabcd",
544            0,
545            regex!(['b' 'c' 'd']?),
546            Span { beg: 0, len: 0 }
547        );
548        test_t!(
549            ctx,
550            "dbcd",
551            0,
552            regex!(['b' 'c' 'd']*),
553            Span { beg: 0, len: 4 }
554        );
555        test_t!(
556            ctx,
557            "aeuyf",
558            0,
559            regex!(['b' 'c' 'd']*),
560            Span { beg: 0, len: 0 }
561        );
562        test_t!(
563            ctx,
564            "dabcd",
565            0,
566            regex!(['b' 'c' 'd']+),
567            Span { beg: 0, len: 1 }
568        );
569        test_t!(
570            ctx,
571            "dbcdfff",
572            0,
573            regex!(['b' 'c' 'd']+),
574            Span { beg: 0, len: 4 }
575        );
576        test_t!(ctx, "abcd", 0, regex!(['b' 'c' 'd']+));
577        test_t!(
578            ctx,
579            "dbcd",
580            0,
581            regex!(['b' 'c' 'd']{4}),
582            Span { beg: 0, len: 4 }
583        );
584        test_t!(
585            ctx,
586            "dbcdccc",
587            0,
588            regex!(['b' 'c' 'd']{4,}),
589            Span { beg: 0, len: 7 }
590        );
591        test_t!(
592            ctx,
593            "dbcdbb",
594            0,
595            regex!(['b' 'c' 'd']{4,7}),
596            Span { beg: 0, len: 6 }
597        );
598        Ok(())
599    }
600
601    fn test_char() -> Result<(), crate::err::Error> {
602        let mut ctx = RegexCtx::new("");
603
604        test_t!(ctx, "a", 0, regex!(a), Span { beg: 0, len: 1 });
605        test_t!(ctx, "a", 0, regex!('a'), Span { beg: 0, len: 1 });
606        test_t!(ctx, "a", 0, regex!(a?), Span { beg: 0, len: 1 });
607        test_t!(ctx, "a", 0, regex!('a'?), Span { beg: 0, len: 1 });
608        test_t!(ctx, "你", 0, regex!(你), Span { beg: 0, len: 3 });
609        test_t!(ctx, "你you", 0, regex!('你'), Span { beg: 0, len: 3 });
610        test_t!(ctx, "@", 0, regex!('@'), Span { beg: 0, len: 1 });
611        test_t!(ctx, "der", 0, regex!(a?), Span { beg: 0, len: 0 });
612        test_t!(ctx, "", 0, regex!('a'?), Span { beg: 0, len: 0 });
613        test_t!(ctx, "a", 0, regex!(a*), Span { beg: 0, len: 1 });
614        test_t!(ctx, "aaaaaee", 0, regex!('a'*), Span { beg: 0, len: 5 });
615        test_t!(ctx, "cde", 0, regex!(a*), Span { beg: 0, len: 0 });
616        test_t!(ctx, "aaaaee", 0, regex!('a'+), Span { beg: 0, len: 4 });
617        test_t!(ctx, "你你你", 0, regex!(你+), Span { beg: 0, len: 9 });
618        test_t!(ctx, "我你你你", 0, regex!(你+));
619        test_t!(ctx, "aaaaee", 0, regex!('a'{2}), Span { beg: 0, len: 2 });
620        test_t!(ctx, "你你你", 0, regex!(你{2}), Span { beg: 0, len: 6 });
621        test_t!(ctx, "你", 0, regex!(你{2}));
622        test_t!(ctx, "aaaaee", 0, regex!('a'{2,}), Span { beg: 0, len: 4 });
623        test_t!(ctx, "你你你", 0, regex!(你{2,}), Span { beg: 0, len: 9 });
624        test_t!(ctx, "你", 0, regex!(你{2,}));
625        test_t!(ctx, "aaaaee", 0, regex!('a'{2,3}), Span { beg: 0, len: 3 });
626        test_t!(
627            ctx,
628            "你你你你你啊",
629            0,
630            regex!(你{2,4}),
631            Span { beg: 0, len: 12 }
632        );
633        test_t!(ctx, "你啊", 0, regex!(你{2,4}));
634
635        Ok(())
636    }
637
638    fn test_space() -> Result<(), crate::err::Error> {
639        let mut ctx = RegexCtx::new("");
640
641        test_t!(ctx, "\tcd", 0, regex!(), Span { beg: 0, len: 1 });
642        test_t!(ctx, "\tdwq", 0, regex!(?), Span { beg: 0, len: 1 });
643        test_t!(ctx, "dwq", 0, regex!(?), Span { beg: 0, len: 0 });
644        test_t!(ctx, "\t\n\rdda", 0, regex!(*), Span { beg: 0, len: 3 });
645        test_t!(ctx, "dda", 0, regex!(*), Span { beg: 0, len: 0 });
646        test_t!(ctx, "\t\n\rdda", 0, regex!(+), Span { beg: 0, len: 3 });
647        test_t!(ctx, "\tdda", 0, regex!(+), Span { beg: 0, len: 1 });
648        test_t!(ctx, "dda", 0, regex!(+));
649        test_t!(ctx, " \u{A0}dda", 0, regex!({ 2 }), Span { beg: 0, len: 3 });
650        test_t!(ctx, "\u{A0}dda", 0, regex!({ 2 }));
651        test_t!(ctx, "\t\rdda", 0, regex!({2,}), Span { beg: 0, len: 2 });
652        test_t!(
653            ctx,
654            "\t\r\u{A0}dda",
655            0,
656            regex!({2,}),
657            Span { beg: 0, len: 4 }
658        );
659        test_t!(ctx, "dda", 0, regex!());
660        test_t!(ctx, "\t\ndda", 0, regex!({2,3}), Span { beg: 0, len: 2 });
661        test_t!(
662            ctx,
663            "\t\r\u{A0}dda",
664            0,
665            regex!({2,3}),
666            Span { beg: 0, len: 4 }
667        );
668        test_t!(
669            ctx,
670            "\t\r \u{A0}dda",
671            0,
672            regex!({2,3}),
673            Span { beg: 0, len: 3 }
674        );
675        test_t!(ctx, " dda", 0, regex!({2,3}));
676
677        Ok(())
678    }
679}