Skip to main content

Crate static_automata

Crate static_automata 

Source
Expand description

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

Structs§

Utf8Error
UTF-8 decoding error.

Functions§

decode_utf8_char
Decode an UTF-8 encoded char from the given bytes at offset i.

Attribute Macros§

grammar
Grammar module annotation.

Derive Macros§

Validate
Derive grammar validation functions.