neure/re/ctor/
if.rs

1use std::fmt::Debug;
2use std::marker::PhantomData;
3
4use crate::ctx::Context;
5use crate::ctx::CtxGuard;
6use crate::ctx::Match;
7use crate::ctx::Span;
8use crate::err::Error;
9use crate::re::def_not;
10use crate::re::trace;
11use crate::re::Ctor;
12use crate::re::Extract;
13use crate::re::Handler;
14use crate::re::Regex;
15
16///
17/// Construct a branch struct base on the test `I`(Fn(&C) -> Result<bool, Error>).
18///
19/// # Ctor
20///
21/// Return the result of `P` if `I` return true, otherwise return `E`.
22///
23/// # Example
24///
25/// ```
26/// # use neure::prelude::*;
27/// #
28/// # fn main() -> color_eyre::Result<()> {
29/// #     color_eyre::install()?;
30///     let re1 = "google".sep_once(".", "com".or("is")).pat();
31///     let re2 = "google"
32///         .sep_once(".", "co".sep_once(".", "kr".or("jp")))
33///         .pat();
34///     // test the `orig` before match
35///     let re = re2.r#if(
36///         |ctx: &CharsCtx| ctx.orig().map(|v| v.ends_with("jp") || v.ends_with("kr")),
37///         re1,
38///     );
39///
40///     assert_eq!(CharsCtx::new("google.com").ctor(&re)?, "google.com");
41///     assert_eq!(CharsCtx::new("google.is").ctor(&re)?, "google.is");
42///     assert_eq!(CharsCtx::new("google.co.jp").ctor(&re)?, "google.co.jp");
43///     assert_eq!(CharsCtx::new("google.co.kr").ctor(&re)?, "google.co.kr");
44///     Ok(())
45/// # }
46/// ```
47#[derive(Default, Copy)]
48pub struct IfRegex<C, P, I, E> {
49    pat: P,
50    r#if: I,
51    r#else: E,
52    marker: PhantomData<C>,
53}
54
55def_not!(IfRegex<C, P, I, E>);
56
57impl<C, P, I, E> Debug for IfRegex<C, P, I, E>
58where
59    P: Debug,
60    I: Debug,
61    E: Debug,
62{
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        f.debug_struct("IfRegex")
65            .field("pat", &self.pat)
66            .field("r#if", &self.r#if)
67            .field("r#else", &self.r#else)
68            .finish()
69    }
70}
71
72impl<C, P, I, E> Clone for IfRegex<C, P, I, E>
73where
74    P: Clone,
75    I: Clone,
76    E: Clone,
77{
78    fn clone(&self) -> Self {
79        Self {
80            pat: self.pat.clone(),
81            r#if: self.r#if.clone(),
82            r#else: self.r#else.clone(),
83            marker: self.marker,
84        }
85    }
86}
87
88impl<C, P, I, E> IfRegex<C, P, I, E> {
89    pub fn new(pat: P, r#if: I, r#else: E) -> Self {
90        Self {
91            pat,
92            r#if,
93            r#else,
94            marker: PhantomData,
95        }
96    }
97
98    pub fn pat(&self) -> &P {
99        &self.pat
100    }
101
102    pub fn pat_mut(&mut self) -> &mut P {
103        &mut self.pat
104    }
105
106    pub fn r#if(&self) -> &I {
107        &self.r#if
108    }
109
110    pub fn r#if_mut(&mut self) -> &mut I {
111        &mut self.r#if
112    }
113
114    pub fn r#else(&self) -> &E {
115        &self.r#else
116    }
117
118    pub fn else_mut(&mut self) -> &mut E {
119        &mut self.r#else
120    }
121
122    pub fn set_pat(&mut self, pat: P) -> &mut Self {
123        self.pat = pat;
124        self
125    }
126
127    pub fn set_if(&mut self, r#if: I) -> &mut Self {
128        self.r#if = r#if;
129        self
130    }
131
132    pub fn set_else(&mut self, r#else: E) -> &mut Self {
133        self.r#else = r#else;
134        self
135    }
136}
137
138impl<'a, C, P, I, E, M, O, H, A> Ctor<'a, C, M, O, H, A> for IfRegex<C, P, I, E>
139where
140    P: Ctor<'a, C, M, O, H, A>,
141    E: Ctor<'a, C, M, O, H, A>,
142    C: Context<'a> + Match<C>,
143    I: Fn(&C) -> Result<bool, Error>,
144    H: Handler<A, Out = M, Error = Error>,
145    A: Extract<'a, C, Span, Out<'a> = A, Error = Error>,
146{
147    #[inline(always)]
148    fn construct(&self, ctx: &mut C, func: &mut H) -> Result<O, Error> {
149        let mut g = CtxGuard::new(ctx);
150        let beg = g.beg();
151        let ret = trace!("if", beg, (self.r#if)(g.ctx())?);
152        let ret = if ret {
153            trace!("if", beg @ "true", self.pat.construct(g.ctx(), func))
154        } else {
155            trace!("if", beg @ "false", self.r#else.construct(g.reset().ctx(), func))
156        };
157
158        trace!("if", beg -> g.end(), ret.is_ok());
159        g.process_ret(ret)
160    }
161}
162
163impl<'a, C, P, I, E> Regex<C> for IfRegex<C, P, I, E>
164where
165    P: Regex<C, Ret = Span>,
166    E: Regex<C, Ret = Span>,
167    C: Context<'a> + Match<C>,
168    I: Fn(&C) -> Result<bool, Error>,
169{
170    type Ret = P::Ret;
171
172    #[inline(always)]
173    fn try_parse(&self, ctx: &mut C) -> Result<Self::Ret, Error> {
174        let mut g = CtxGuard::new(ctx);
175        let beg = g.beg();
176        let ret = trace!("if", beg, (self.r#if)(g.ctx())?);
177        let ret = if ret {
178            trace!("if", beg @ "true", g.try_mat(&self.pat))
179        } else {
180            trace!("if", beg @ "false", g.try_mat(&self.r#else))
181        };
182
183        trace!("if", beg => g.end(), ret)
184    }
185}
186
187pub fn branch<'a, C, P, I, E>(r#if: I, re: P, r#else: E) -> IfRegex<C, P, I, E>
188where
189    C: Context<'a> + Match<C>,
190    E: Regex<C, Ret = Span>,
191    P: Regex<C, Ret = Span>,
192    I: Fn(&C) -> Result<bool, Error>,
193{
194    IfRegex::new(re, r#if, r#else)
195}