whitehole/combinator/decorator/
state.rs

1use super::{create_closure_decorator, Accepted};
2use crate::{
3  action::{Action, Input, Output},
4  combinator::Combinator,
5  digest::Digest,
6  instant::Instant,
7};
8
9create_closure_decorator!(Prepare, "See [`Combinator::prepare`].");
10create_closure_decorator!(Then, "See [`Combinator::then`].");
11create_closure_decorator!(Catch, "See [`Combinator::catch`].");
12create_closure_decorator!(Finally, "See [`Combinator::finally`].");
13
14unsafe impl<T: Action, D: Fn(Input<&Instant<&T::Text>, &mut T::State, &mut T::Heap>)> Action
15  for Prepare<T, D>
16{
17  type Text = T::Text;
18  type State = T::State;
19  type Heap = T::Heap;
20  type Value = T::Value;
21
22  #[inline]
23  fn exec(
24    &self,
25    mut input: Input<&Instant<&Self::Text>, &mut Self::State, &mut Self::Heap>,
26  ) -> Option<Output<Self::Value>> {
27    (self.inner)(input.reborrow());
28    self.action.exec(input)
29  }
30}
31
32unsafe impl<
33    T: Action<Text: Digest>,
34    D: Fn(Accepted<&Instant<&T::Text>, &mut T::State, &mut T::Heap, &T::Value>),
35  > Action for Then<T, D>
36{
37  type Text = T::Text;
38  type State = T::State;
39  type Heap = T::Heap;
40  type Value = T::Value;
41
42  #[inline]
43  fn exec(
44    &self,
45    mut input: Input<&Instant<&Self::Text>, &mut Self::State, &mut Self::Heap>,
46  ) -> Option<Output<Self::Value>> {
47    self.action.exec(input.reborrow()).inspect(|output| {
48      (self.inner)(unsafe {
49        Accepted::new_unchecked(input.instant, output.as_ref(), input.state, input.heap)
50      });
51    })
52  }
53}
54
55unsafe impl<T: Action, D: Fn(Input<&Instant<&T::Text>, &mut T::State, &mut T::Heap>)> Action
56  for Catch<T, D>
57{
58  type Text = T::Text;
59  type State = T::State;
60  type Heap = T::Heap;
61  type Value = T::Value;
62
63  #[inline]
64  fn exec(
65    &self,
66    mut input: Input<&Instant<&Self::Text>, &mut Self::State, &mut Self::Heap>,
67  ) -> Option<Output<Self::Value>> {
68    let output = self.action.exec(input.reborrow());
69    if output.is_none() {
70      (self.inner)(input);
71    }
72    output
73  }
74}
75
76unsafe impl<T: Action, D: Fn(Input<&Instant<&T::Text>, &mut T::State, &mut T::Heap>)> Action
77  for Finally<T, D>
78{
79  type Text = T::Text;
80  type State = T::State;
81  type Heap = T::Heap;
82  type Value = T::Value;
83
84  #[inline]
85  fn exec(
86    &self,
87    mut input: Input<&Instant<&Self::Text>, &mut Self::State, &mut Self::Heap>,
88  ) -> Option<Output<Self::Value>> {
89    let output = self.action.exec(input.reborrow());
90    (self.inner)(input);
91    output
92  }
93}
94
95impl<T> Combinator<T> {
96  /// Create a new combinator to modify [`Input::state`] and [`Input::heap`]
97  /// before being executed.
98  /// # Examples
99  /// ```
100  /// # use whitehole::{action::Action, combinator::Combinator};
101  /// # struct MyState { value: i32 }
102  /// # fn t(combinator: Combinator<impl Action<Text=str, State=MyState>>) {
103  /// combinator.prepare(|input| input.state.value += 1)
104  /// # ;}
105  /// ```
106  #[inline]
107  pub fn prepare<F: Fn(Input<&Instant<&T::Text>, &mut T::State, &mut T::Heap>)>(
108    self,
109    modifier: F,
110  ) -> Combinator<Prepare<T, F>>
111  where
112    T: Action,
113  {
114    Combinator::new(Prepare::new(self.action, modifier))
115  }
116
117  /// Create a new combinator to modify [`Input::state`] and [`Input::heap`]
118  /// after being accepted.
119  /// # Examples
120  /// ```
121  /// # use whitehole::{action::Action, combinator::Combinator};
122  /// # struct MyState { value: i32 }
123  /// # fn t(combinator: Combinator<impl Action<Text=str, State=MyState>>) {
124  /// combinator.then(|input| input.state.value += 1)
125  /// # ;}
126  /// ```
127  #[inline]
128  pub fn then<F: Fn(Accepted<&Instant<&T::Text>, &mut T::State, &mut T::Heap, &T::Value>)>(
129    self,
130    modifier: F,
131  ) -> Combinator<Then<T, F>>
132  where
133    T: Action,
134  {
135    Combinator::new(Then::new(self.action, modifier))
136  }
137
138  /// Create a new combinator to modify [`Input::state`] and [`Input::heap`]
139  /// after being rejected.
140  /// # Examples
141  /// ```
142  /// # use whitehole::{action::Action, combinator::Combinator};
143  /// # struct MyState { value: i32 }
144  /// # fn t(combinator: Combinator<impl Action<Text=str, State=MyState>>) {
145  /// combinator.catch(|input| input.state.value += 1)
146  /// # ;}
147  /// ```
148  #[inline]
149  pub fn catch<F: Fn(Input<&Instant<&T::Text>, &mut T::State, &mut T::Heap>)>(
150    self,
151    modifier: F,
152  ) -> Combinator<Catch<T, F>>
153  where
154    T: Action,
155  {
156    Combinator::new(Catch::new(self.action, modifier))
157  }
158
159  /// Create a new combinator to modify [`Input::state`] and [`Input::heap`]
160  /// after the combinator is executed,
161  /// no matter whether it is accepted or rejected.
162  /// # Examples
163  /// ```
164  /// # use whitehole::{action::Action, combinator::Combinator};
165  /// # struct MyState { value: i32 }
166  /// # fn t(combinator: Combinator<impl Action<Text=str, State=MyState>>) {
167  /// combinator.finally(|input| input.state.value += 1)
168  /// # ;}
169  /// ```
170  #[inline]
171  pub fn finally<F: Fn(Input<&Instant<&T::Text>, &mut T::State, &mut T::Heap>)>(
172    self,
173    modifier: F,
174  ) -> Combinator<Finally<T, F>>
175  where
176    T: Action,
177  {
178    Combinator::new(Finally::new(self.action, modifier))
179  }
180}
181
182#[cfg(test)]
183mod tests {
184  use super::*;
185  use crate::{contextual, digest::Digest, instant::Instant};
186  use std::{fmt::Debug, ops::RangeFrom, slice::SliceIndex};
187
188  #[derive(Debug, Default, PartialEq, Eq)]
189  pub struct State {
190    from: i32,
191    to: i32,
192  }
193
194  fn helper<Text: ?Sized + Digest>(
195    action: impl Action<Text = Text, State = State, Heap = (), Value = ()>,
196    input: &Text,
197    state: &mut State,
198    digested: Option<usize>,
199  ) where
200    RangeFrom<usize>: SliceIndex<Text, Output = Text>,
201  {
202    assert_eq!(
203      action
204        .exec(Input {
205          instant: &Instant::new(input),
206          state,
207          heap: &mut ()
208        })
209        .map(|o| o.digested),
210      digested
211    )
212  }
213
214  contextual!(State, ());
215
216  fn accepter(
217  ) -> Combinator<impl Action<Text = str, State = State, Heap = (), Value = ()> + Debug + Copy> {
218    wrap(|input| {
219      input.state.to = input.state.from;
220      input.instant.accept(1)
221    })
222  }
223  fn accepter_bytes(
224  ) -> Combinator<impl Action<Text = [u8], State = State, Heap = (), Value = ()> + Debug + Copy> {
225    bytes::wrap(|input| {
226      input.state.to = input.state.from;
227      input.instant.accept(1)
228    })
229  }
230
231  fn rejecter(
232  ) -> Combinator<impl Action<Text = str, State = State, Heap = (), Value = ()> + Debug + Copy> {
233    wrap(|input| {
234      input.state.to = input.state.from;
235      None
236    })
237  }
238  fn rejecter_bytes(
239  ) -> Combinator<impl Action<Text = [u8], State = State, Heap = (), Value = ()> + Debug + Copy> {
240    bytes::wrap(|input| {
241      input.state.to = input.state.from;
242      None
243    })
244  }
245
246  #[test]
247  fn combinator_prepare() {
248    // accepted
249    let mut state = State::default();
250    helper(
251      accepter().prepare(|input| {
252        input.state.from = 1;
253      }),
254      "123",
255      &mut state,
256      Some(1),
257    );
258    assert_eq!(state, State { from: 1, to: 1 });
259    let mut state = State::default();
260    helper(
261      accepter_bytes().prepare(|input| {
262        input.state.from = 1;
263      }),
264      b"123",
265      &mut state,
266      Some(1),
267    );
268    assert_eq!(state, State { from: 1, to: 1 });
269
270    // rejected
271    let mut state = State::default();
272    helper(
273      rejecter().prepare(|input| {
274        input.state.from = 1;
275      }),
276      "123",
277      &mut state,
278      None,
279    );
280    assert_eq!(state, State { from: 1, to: 1 });
281    let mut state = State::default();
282    helper(
283      rejecter_bytes().prepare(|input| {
284        input.state.from = 1;
285      }),
286      b"123",
287      &mut state,
288      None,
289    );
290    assert_eq!(state, State { from: 1, to: 1 });
291
292    // debug
293    let _ = format!("{:?}", accepter().prepare(|_| {}));
294    // copy & clone
295    let c = accepter().prepare(|_| {});
296    let _c = c;
297    let _c = c.clone();
298  }
299
300  #[test]
301  fn combinator_then() {
302    // accepted
303    let mut state = State::default();
304    helper(
305      accepter().then(|input| {
306        input.state.from = 1;
307      }),
308      "123",
309      &mut state,
310      Some(1),
311    );
312    assert_eq!(state, State { from: 1, to: 0 });
313    let mut state = State::default();
314    helper(
315      accepter_bytes().then(|input| {
316        input.state.from = 1;
317      }),
318      b"123",
319      &mut state,
320      Some(1),
321    );
322    assert_eq!(state, State { from: 1, to: 0 });
323
324    // rejected
325    let mut state = State::default();
326    helper(
327      rejecter().then(|input| {
328        input.state.from = 1;
329      }),
330      "123",
331      &mut state,
332      None,
333    );
334    assert_eq!(state, State { from: 0, to: 0 });
335    let mut state = State::default();
336    helper(
337      rejecter_bytes().then(|input| {
338        input.state.from = 1;
339      }),
340      b"123",
341      &mut state,
342      None,
343    );
344    assert_eq!(state, State { from: 0, to: 0 });
345
346    // debug
347    let _ = format!("{:?}", accepter().then(|_| {}));
348    // copy & clone
349    let c = accepter().then(|_| {});
350    let _c = c;
351    let _c = c.clone();
352  }
353
354  #[test]
355  fn combinator_catch() {
356    // accepted
357    let mut state = State::default();
358    helper(
359      accepter().catch(|input| {
360        input.state.from = 1;
361      }),
362      "123",
363      &mut state,
364      Some(1),
365    );
366    assert_eq!(state, State { from: 0, to: 0 });
367    let mut state = State::default();
368    helper(
369      accepter_bytes().catch(|input| {
370        input.state.from = 1;
371      }),
372      b"123",
373      &mut state,
374      Some(1),
375    );
376    assert_eq!(state, State { from: 0, to: 0 });
377
378    // rejected
379    let mut state = State::default();
380    helper(
381      rejecter().catch(|input| {
382        input.state.from = 1;
383      }),
384      "123",
385      &mut state,
386      None,
387    );
388    assert_eq!(state, State { from: 1, to: 0 });
389    let mut state = State::default();
390    helper(
391      rejecter_bytes().catch(|input| {
392        input.state.from = 1;
393      }),
394      b"123",
395      &mut state,
396      None,
397    );
398    assert_eq!(state, State { from: 1, to: 0 });
399
400    // debug
401    let _ = format!("{:?}", accepter().catch(|_| {}));
402    // copy & clone
403    let c = accepter().catch(|_| {});
404    let _c = c;
405    let _c = c.clone();
406  }
407
408  #[test]
409  fn combinator_finally() {
410    // accepted
411    let mut state = State::default();
412    helper(
413      accepter().finally(|input| {
414        input.state.to = 1;
415      }),
416      "123",
417      &mut state,
418      Some(1),
419    );
420    assert_eq!(state, State { from: 0, to: 1 });
421    let mut state = State::default();
422    helper(
423      accepter_bytes().finally(|input| {
424        input.state.to = 1;
425      }),
426      b"123",
427      &mut state,
428      Some(1),
429    );
430    assert_eq!(state, State { from: 0, to: 1 });
431
432    // rejected
433    let mut state = State::default();
434    helper(
435      rejecter().finally(|input| {
436        input.state.to = 1;
437      }),
438      "123",
439      &mut state,
440      None,
441    );
442    assert_eq!(state, State { from: 0, to: 1 });
443    let mut state = State::default();
444    helper(
445      rejecter_bytes().finally(|input| {
446        input.state.to = 1;
447      }),
448      b"123",
449      &mut state,
450      None,
451    );
452    assert_eq!(state, State { from: 0, to: 1 });
453
454    // debug
455    let _ = format!("{:?}", accepter().finally(|_| {}));
456    // copy & clone
457    let c = accepter().finally(|_| {});
458    let _c = c;
459    let _c = c.clone();
460  }
461}