rusty_alto/combinators/
mapped.rs1use crate::{BottomUpTa, DetBottomUpTa, IndexedBottomUpTa, Symbol};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub struct Mapped<A, F> {
10 pub inner: A,
12 pub map: F,
14}
15
16impl<A, F> Mapped<A, F> {
17 pub fn new(inner: A, map: F) -> Self {
19 Self { inner, map }
20 }
21}
22
23impl<A, F> BottomUpTa for Mapped<A, F>
24where
25 A: BottomUpTa,
26 F: Fn(Symbol) -> Symbol,
27{
28 type State = A::State;
29
30 fn step(&self, f: Symbol, children: &[Self::State], out: &mut dyn FnMut(Self::State)) {
31 self.inner.step((self.map)(f), children, out);
32 }
33
34 fn is_accepting(&self, q: &Self::State) -> bool {
35 self.inner.is_accepting(q)
36 }
37}
38
39impl<A, F> DetBottomUpTa for Mapped<A, F>
40where
41 A: DetBottomUpTa,
42 F: Fn(Symbol) -> Symbol,
43{
44 fn step_det(&self, f: Symbol, children: &[Self::State]) -> Option<Self::State> {
45 self.inner.step_det((self.map)(f), children)
46 }
47}
48
49impl<A, F> IndexedBottomUpTa for Mapped<A, F>
50where
51 A: IndexedBottomUpTa,
52 F: Fn(Symbol) -> Symbol,
53{
54 fn step_partial(
55 &self,
56 f: Symbol,
57 position: usize,
58 state_at_position: &Self::State,
59 out: &mut dyn FnMut(&[Self::State], Self::State),
60 ) {
61 self.inner
62 .step_partial((self.map)(f), position, state_at_position, out);
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69 use crate::{ExplicitBuilder, StateId};
70
71 #[test]
72 fn maps_symbols_for_deterministic_steps() {
73 let external_a = Symbol(7);
74 let inner_a = Symbol(0);
75 let mut builder = ExplicitBuilder::new();
76 let q = builder.new_state();
77 builder.add_rule(inner_a, vec![], q);
78 let mapped = Mapped::new(
79 builder.build(),
80 move |f| {
81 if f == external_a { inner_a } else { f }
82 },
83 );
84
85 assert_eq!(mapped.step_det(external_a, &[]), Some(q));
86 }
87
88 #[test]
89 fn maps_symbols_for_indexed_steps() {
90 let external_f = Symbol(8);
91 let inner_f = Symbol(1);
92 let mut builder = ExplicitBuilder::new();
93 let q0 = builder.new_state();
94 let q1 = builder.new_state();
95 builder.add_rule(inner_f, vec![q0], q1);
96 let mapped = Mapped::new(
97 builder.build(),
98 move |f| {
99 if f == external_f { inner_f } else { f }
100 },
101 );
102
103 let mut found = Vec::<(Vec<StateId>, StateId)>::new();
104 mapped.step_partial(external_f, 0, &q0, &mut |children, result| {
105 found.push((children.to_vec(), result));
106 });
107
108 assert_eq!(found, vec![(vec![q0], q1)]);
109 }
110}