static-automata 1.0.0

Derive macro for static regular grammar
Documentation
# Static Automata: Compile-time DFA generation framework.

[![Build](https://img.shields.io/github/actions/workflow/status/timothee-haudebourg/static-automata/ci.yml?branch=main&style=flat-square)](https://github.com/timothee-haudebourg/static-automata/actions)
[![Crate informations](https://img.shields.io/crates/v/static-automata.svg?style=flat-square)](https://crates.io/crates/static-automata)
[![License](https://img.shields.io/crates/l/static-automata.svg?style=flat-square)](https://github.com/timothee-haudebourg/static-automata#license)
[![Documentation](https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square)](https://docs.rs/static-automata)

<!-- cargo-rdme start -->

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();
}
```

<!-- cargo-rdme end -->

## 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.