#![feature(offset_of_enum)]
use nearest::{FixedBuf, Flat, NearList, Region, empty, list};
#[derive(Flat, Copy, Clone, Debug, PartialEq, Eq)]
#[repr(C, u8)]
enum Match {
Char(u8),
Any,
}
#[derive(Flat, Debug)]
struct Transition {
cond: Match,
target: u32,
}
#[derive(Flat, Debug)]
struct State {
accept: bool,
edges: NearList<Transition>,
}
#[derive(Flat, Debug)]
struct Fsm {
states: NearList<State>,
}
fn simulate(fsm: &Fsm, input: &[u8]) -> bool {
let mut current: u32 = 0;
for &byte in input {
let state = &fsm.states[current as usize];
let mut matched = false;
for edge in &state.edges {
let ok = match edge.cond {
Match::Char(c) => c == byte,
Match::Any => true,
};
if ok {
current = edge.target;
matched = true;
break;
}
}
if !matched {
return false; }
}
fsm.states[current as usize].accept
}
fn main() {
let s0 = Region::new(State::make(false, list([Transition::make(Match::Char(b'a'), 1)])));
let s1 = Region::new(State::make(false, list([Transition::make(Match::Any, 2)])));
let s2 = Region::new(State::make(false, list([Transition::make(Match::Char(b'b'), 3)])));
let s3 = Region::new(State::make(true, empty()));
let mut region: Region<Fsm, FixedBuf<512>> =
Region::new_in(Fsm::make(list([&*s0, &*s1, &*s2, &*s3])));
println!("=== FSM for pattern 'a.b' ===");
println!("states: {}", region.states.len());
for (i, state) in region.states.iter().enumerate() {
println!(" state {}: accept={}, edges={}", i, state.accept, state.edges.len());
}
let tests: &[(&[u8], bool)] = &[
(b"axb", true),
(b"a1b", true),
(b"aab", true),
(b"ab", false), (b"axc", false), (b"bxa", false), (b"", false), ];
println!("\n=== simulation ===");
for (input, expected) in tests {
let input_str = core::str::from_utf8(input).unwrap_or("?");
let result = simulate(®ion, input);
println!(
" \"{}\" -> {} {}",
input_str,
result,
if result == *expected { "ok" } else { "FAIL" }
);
assert_eq!(result, *expected);
}
region.session(|s| {
let state3_edges = s.nav(s.root(), |fsm| &fsm.states[3].edges);
s.extend_list(state3_edges, [Transition::make(Match::Char(b'b'), 3)]);
});
println!("\n=== after adding 'b' loop on accept state ===");
let extra_tests: &[(&[u8], bool)] = &[
(b"axb", true),
(b"axbb", true),
(b"axbbb", true),
(b"axbc", false), ];
for (input, expected) in extra_tests {
let input_str = core::str::from_utf8(input).unwrap_or("?");
let result = simulate(®ion, input);
println!(
" \"{}\" -> {} {}",
input_str,
result,
if result == *expected { "ok" } else { "FAIL" }
);
assert_eq!(result, *expected);
}
println!("\nbyte_len: {}", region.byte_len());
}