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#[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}