static-automata 1.0.2

Derive macro for static regular grammar
Documentation

Static Automata: Compile-time DFA generation framework.

Build Crate informations License Documentation

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.

Example

/// 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):

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:

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

use build_automata::build_automata;

fn main() {
  build_automata();
}

License

Licensed under either of

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.