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 core of the crate is the Pattern trait. Patterns can be combined using combinatorial logic to express more complex rules about what a byte (or sequence of bytes) should look like.

The other part of the crate is the Parser struct. It provides a simpler way to parse a slice of bytes by continuously matching patterns against it.

§Examples

HTTP request line

Say you want 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, Parser};

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

let mut parser = Parser::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 method = parser.try_match(method_pattern)?;
parser.try_match(" ")?;
let request_target = parser.try_match(request_target_pattern)?;
parser.try_match(" ")?;
let version = parser.try_match(version_pattern)?;
parser.try_match("\r\n".and(bparse::end))?;

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, Parser, range, end};
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 = range(b'0', b'9').or(range(b'A', b'F')).or(range(b'a', b'f')).repeats(2);

  let mut parser = Parser::new(input.as_bytes());

  parser.try_match("#")?;
  let red = parser.try_match(hexbyte)?;
  let green = parser.try_match(hexbyte)?;
  let blue = parser.try_match(hexbyte)?;
  parser.try_match(end)?;

  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
  • Expresses pattern negation
  • Returns a pattern that will match any one of the bytes in alternatives
  • Expresses an optional pattern
  • Returns a pattern that will match any byte in the closed interval [lo, hi]