# Static Automata: Compile-time DFA generation framework.
[](https://github.com/timothee-haudebourg/static-automata-rs/actions)
[](https://crates.io/crates/static-automata)
[](https://github.com/timothee-haudebourg/static-automata-rs#license)
[](https://docs.rs/static-automata)
This frameworks helps you define validation functions based on deterministic
finite automata (DFAs) generated from ABNF grammars.
It works as follows:
- Declare a `mod` item annotated with the `#[grammar]` macro specifying an
ABNF grammar (either from a file, or in the doc comments).
- Use the `cargo build-automata` command line interface to generate the
declared module file, containing the grammar compiled into a deterministic
finite automaton. Alternatively you can call the [`build-automata`]
library directly from a `build.rs` script.
- Use the validation functions provided in the generated module directly,
or use the `Validate` derive macro to bind them to custom types.
[`build-automata`]: https://crates.io/crates/build-automata
### Example
```rust
/// Automata module.
///
/// This module file is generated by the command line interface or builder
/// library. It contains an `Iri` type definition for the `IRI` production
/// of the `iri.abnf` that we exported here, with a `validate_bytes` and a
/// `validate_bytes` const function.
///
/// The attribute macro itself doesn't generate anything, but replaces this
/// item with an external module import `mod automata;`.
use static_automata::{grammar, Validate};
#[grammar(file = "iri.abnf", export("IRI"))]
mod automata {}
/// Derive the `validate_bytes` and `validate_str` methods from the
/// `automata::Iri` automaton.
#[derive(Validate)]
#[automaton(automata::Iri)]
struct Foo;
fn main() {
// Byte string validation.
assert!(Foo::validate_bytes(b"https://example.com").is_ok());
// String validation.
assert!(Foo::validate_str("https://example.com").is_ok());
// The validation functions are `const` compatible.
const _: () = {
assert!(Foo::validate_bytes(b"https://example.com").is_ok());
assert!(Foo::validate_str("https://example.com").is_ok());
};
}
```
### Why not compile the grammars through the attribute macro?
Compiling a grammar requires determinizing a potentially large automaton,
which is computationally very expensive.
### Command line interface
You can install it with `cargo install cargo-build-automata` then use it
when you need to re-generate the autamata (e.g. when the associated grammar
changes):
```bash
cargo build-automata
```
Be careful, this will override the content of the modules annotated with the
`#[grammar]` attribute macro. If you're not sure which file will be
overriden you can run the cli with the `-d`/`--dry-run` flag:
```bash
cargo build-automata -d
```
It will compile the grammars, but not write anything.
### Build script
The advantage of the command line interface is that it allows you to ship
the automata already compiled with your library/application. However you
might prefer to compile the automata on the user machine, using a `build.rs`
script. To do that you can use the [`build-automata`] library (the cli is
basically a wrapper around this library).
```rust
use build_automata::build_automata;
fn main() {
build_automata();
}
```
## License
Licensed under either of
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.