Crate bparse

source ·
Expand description

This crate provides utilites for parsing byte slices. The API borrows some concepts from other parser-combinator crates but heavily simplifies things by eschewing error management and focusing exclusively on parsing byte slices.

§Overview

The crate’s entry point is the Matches struct. It contains an array of input segments that have been matched. The array is populated by repeatedly calling .add() with a pattern argument.

Patterns can be combined using combinatorial logic to express more complex rules about what a byte (or sequence of bytes should look like)

§Examples

HTTP request line

Say you wanted to parse the request line of an HTTP message. There are three important parts to extract: the method, the request target and the protocol version.

GET /hello?value=world HTTP/1.1\r\n

Here is how you would do it:

Note: The rules for parsing http are a bit more nuanced than this

use bparse::{Pattern, Matches};

// This input would probably come from a TcpStream
let input = b"GET /hello?value=world HTTP/1.1\r\n";

let matches = Matches::new(input);

// A method is an alphabetic string with at least one character
let method_pattern = bparse::range(b'a', b'z')
    .or(bparse::range(b'A', b'Z'))
    .repeats(1..);


// A request url must start with a `/` and contains a mix of alphabetic and special characters
let request_target_pattern = "/"
    .and(
        bparse::range(b'a', b'z')
        .or(bparse::range(b'A', b'Z'))
        .or(bparse::oneof("?=/"))
        .repeats(0..)
    );

// We want to match the version exactly
let version_pattern = "HTTP/1.1";

let result = matches
    .pattern(method_pattern)?
    .ignore(" ")?
    .pattern(request_target_pattern)?
    .ignore(" ")?
    .pattern(version_pattern)?
    .ignore("\r\n".and(bparse::end))?;


// Et voila
let [method, request_target, version] = result.0;

assert_eq!(method, b"GET");
assert_eq!(request_target, b"/hello?value=world");
assert_eq!(version, b"HTTP/1.1");

Hexadecimal color parser:

use bparse::{Pattern, Matches};
use std::str::from_utf8;

#[derive(Debug, PartialEq)]
pub struct Color {
  pub red: u8,
  pub green: u8,
  pub blue: u8,
}

fn main() {
  assert_eq!(hex_color("#2F14DF"), Some(Color {
    red: 47,
    green: 20,
    blue: 223,
  }));
}

fn hex_color(input: &str) -> Option<Color> {
  let hexbyte = bparse::range(b'0', b'9')
    .or(bparse::range(b'A', b'F'))
    .or(bparse::range(b'a', b'f'))
    .repeats(2);

  let [red, green, blue] = Matches::new(input.as_bytes())
    .ignore("#")?
    .pattern(hexbyte)?
    .pattern(hexbyte)?
    .pattern(hexbyte)?
    .ignore(bparse::end)?
    .0;

  Some(Color {
    red: u8::from_str_radix(from_utf8(red).unwrap(), 16).unwrap(),
    green: u8::from_str_radix(from_utf8(green).unwrap(), 16).unwrap(),
    blue: u8::from_str_radix(from_utf8(blue).unwrap(), 16).unwrap()
  })
}

Structs§

Traits§

  • Expresses that the implementing type can be used to match a byte slice

Functions§

  • A pattern that fails if the byte at the start of the input is not an ascii alphabetic character
  • A pattern that fails if the byte at the start of the input is not an ascii digit
  • A pattern that fails if the input is not empty
  • A pattern that fails if the byte at the start of the input is not a hexadecimal character
  • Inverse of oneof
  • Returns a pattern that will match any one of the bytes in alternatives
  • Returns a pattern that will match any byte in the closed interval [lo, hi]