#byte-string #lexing #match #codegen #parser #byte-sequences

matchgen

Generate functions to quickly map byte string prefixes to values

2 unstable releases

0.2.0 May 27, 2023
0.1.0 Feb 27, 2023

#1637 in Encoding

Download history 39/week @ 2023-12-21 36/week @ 2023-12-28 12/week @ 2024-01-04 5/week @ 2024-01-11 30/week @ 2024-02-15 27/week @ 2024-02-22 27/week @ 2024-02-29 18/week @ 2024-03-07 12/week @ 2024-03-14 8/week @ 2024-03-21 21/week @ 2024-03-28

60 downloads per month
Used in 5 crates (via htmlize)

MIT/Apache

215KB
446 lines

Generate functions to quickly map byte string prefixes to values

docs.rs Crates.io Rust version 1.60+

TreeMatcher can be used from a build script to generate a matcher function that maps byte sequences to arbitrary values. It returns the mapped value (or None) and the remainder of the input.

For example, suppose you generate a matcher for all HTML entities called entity_matcher():

assert!(entity_matcher(b"×XYZ") == (Some("×"), b"XYZ".as_slice()));
  • The prefixes it checks do not all have to be the same length.
  • If more than one prefix matches, it will return the longest one.
  • If nothing matches, it will return (None, &input).

Since the matchers only check the start of the input, you will want to use iter().position() or the memchr crate to find the start of a potential match.

It can also be configured to accept an iterator over bytes as input instead of a slice.

Simple example

To create a matcher to handle the four basic HTML entities, use a build script like the following:

use matchgen::TreeMatcher;
use std::env;
use std::error::Error;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::Path;

fn main() -> Result<(), Box<dyn Error>> {
    let out_path = Path::new(&env::var("OUT_DIR")?).join("matcher.rs");
    let mut out = BufWriter::new(File::create(out_path)?);

    TreeMatcher::new("pub fn entity_decode", "u8")
        .doc("Decode basic HTML entities.")
        .add(b"&amp;", "b'&'")
        .add(b"&lt;", "b'<'")
        .add(b"&gt;", "b'>'")
        .add(b"&quot;", "b'\"'")
        .render(&mut out)?;

    Ok(())
}

To use the matcher:

include!(concat!(env!("OUT_DIR"), "/matcher.rs"));

fn main() {
    assert_eq!(
      entity_decode(b"&amp; on &amp; on"),
      (Some(b'&'), b" on &amp; on".as_slice()),
    );
}

Development status

This is potentially stable. I’m letting it bake a while to see if I come up with new features or better ways to accomplish the same thing before I release version 1.0.

I am open to suggestions.

License

This project dual-licensed under the Apache 2 and MIT licenses. You may choose to use either.

Contributions

Unless you explicitly state otherwise, any contribution you submit as defined in the Apache 2.0 license shall be dual licensed as above, without any additional terms or conditions.

No runtime deps