1 use super::{Byte, Ref, Tree, Uninhabited};
4 use std::sync::atomic::{AtomicU32, Ordering};
6 /// A non-deterministic finite automaton (NFA) that represents the layout of a type.
7 /// The transmutability of two given types is computed by comparing their `Nfa`s.
8 #[derive(PartialEq, Debug)]
9 pub(crate) struct Nfa<R>
13 pub(crate) transitions: Map<State, Map<Transition<R>, Set<State>>>,
14 pub(crate) start: State,
15 pub(crate) accepting: State,
18 /// The states in a `Nfa` represent byte offsets.
19 #[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
20 pub(crate) struct State(u32);
22 /// The transitions between states in a `Nfa` reflect bit validity.
23 #[derive(Hash, Eq, PartialEq, Clone, Copy)]
24 pub(crate) enum Transition<R>
32 impl fmt::Debug for State {
33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34 write!(f, "S_{}", self.0)
38 impl<R> fmt::Debug for Transition<R>
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 Self::Byte(b) => b.fmt(f),
45 Self::Ref(r) => r.fmt(f),
54 pub(crate) fn unit() -> Self {
55 let transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
56 let start = State::new();
57 let accepting = start;
59 Nfa { transitions, start, accepting }
62 pub(crate) fn from_byte(byte: Byte) -> Self {
63 let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
64 let start = State::new();
65 let accepting = State::new();
67 let source = transitions.entry(start).or_default();
68 let edge = source.entry(Transition::Byte(byte)).or_default();
69 edge.insert(accepting);
71 Nfa { transitions, start, accepting }
74 pub(crate) fn from_ref(r: R) -> Self {
75 let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
76 let start = State::new();
77 let accepting = State::new();
79 let source = transitions.entry(start).or_default();
80 let edge = source.entry(Transition::Ref(r)).or_default();
81 edge.insert(accepting);
83 Nfa { transitions, start, accepting }
86 pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> {
88 Tree::Byte(b) => Self::from_byte(b),
89 Tree::Def(..) => unreachable!(),
90 Tree::Ref(r) => Self::from_ref(r),
92 let mut alts = alts.into_iter().map(Self::from_tree);
93 let mut nfa = alts.next().ok_or(Uninhabited)??;
95 nfa = nfa.union(alt?);
100 let mut nfa = Self::unit();
101 for elt in elts.into_iter().map(Self::from_tree) {
102 nfa = nfa.concat(elt?);
109 /// Concatenate two `Nfa`s.
110 pub(crate) fn concat(self, other: Self) -> Self {
111 if self.start == self.accepting {
113 } else if other.start == other.accepting {
117 let start = self.start;
118 let accepting = other.accepting;
120 let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions;
122 for (source, transition) in other.transitions {
123 let fix_state = |state| if state == other.start { self.accepting } else { state };
124 let entry = transitions.entry(fix_state(source)).or_default();
125 for (edge, destinations) in transition {
126 let entry = entry.entry(edge).or_default();
127 for destination in destinations {
128 entry.insert(fix_state(destination));
133 Self { transitions, start, accepting }
136 /// Compute the union of two `Nfa`s.
137 pub(crate) fn union(self, other: Self) -> Self {
138 let start = self.start;
139 let accepting = self.accepting;
141 let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions.clone();
143 for (&(mut source), transition) in other.transitions.iter() {
144 // if source is starting state of `other`, replace with starting state of `self`
145 if source == other.start {
148 let entry = transitions.entry(source).or_default();
149 for (edge, destinations) in transition {
150 let entry = entry.entry(*edge).or_default();
151 for &(mut destination) in destinations {
152 // if dest is accepting state of `other`, replace with accepting state of `self`
153 if destination == other.accepting {
154 destination = self.accepting;
156 entry.insert(destination);
160 Self { transitions, start, accepting }
163 pub(crate) fn edges_from(&self, start: State) -> Option<&Map<Transition<R>, Set<State>>> {
164 self.transitions.get(&start)
169 pub(crate) fn new() -> Self {
170 static COUNTER: AtomicU32 = AtomicU32::new(0);
171 Self(COUNTER.fetch_add(1, Ordering::SeqCst))