Skip to main content

rusty_alto/combinators/
mapped.rs

1use crate::{BottomUpTa, DetBottomUpTa, IndexedBottomUpTa, Symbol};
2
3/// Symbol-renaming view of an automaton.
4///
5/// `Mapped` is useful when an automaton should be queried under a different
6/// external signature. The mapping is applied to every input symbol before the
7/// wrapped automaton is queried. States are unchanged.
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub struct Mapped<A, F> {
10    /// Wrapped automaton.
11    pub inner: A,
12    /// Function from external symbol IDs to the wrapped automaton's symbol IDs.
13    pub map: F,
14}
15
16impl<A, F> Mapped<A, F> {
17    /// Create a mapped view.
18    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}