Skip to content

Latest commit

 

History

History
131 lines (106 loc) · 7.42 KB

File metadata and controls

131 lines (106 loc) · 7.42 KB
Http Path Template Logo

Http Path Template

crate.io docs.rs MSRV CI Coverage License This crate was developed as part of the Oxidizer project

A parser for the google.api.http path-template grammar.

A path template is the pattern that appears in a google.api.http annotation, for example /shelves/{shelf}/books/{book=**}:archive. This crate turns such a string into a validated, structured PathTemplate — an abstract syntax tree of Segments (literals, *, **, and {field.path=sub-template} Variable bindings) plus an optional custom :verb.

Parsing is zero-copy: the returned PathTemplate borrows from the input string (every literal, field name, and verb is a slice into it), so a parse copies no text and allocates only the top-level segment list.

A template must begin with / and is a /-separated sequence of segments — each / delimits one segment. Literal segments, variable field names, and the custom :verb are preserved and compared verbatim, so the grammar is case-sensitive; the parser performs no case folding.

The grammar mirrors the reference google.api.HttpRule path syntax:

  • a literal segment (shelves) must match verbatim and contain only RFC 3986 pchar characters, with valid %HH escapes; raw * is reserved for the wildcard atoms below and must be percent-encoded in a literal;
  • * (Segment::Single) matches exactly one non-empty segment;
  • ** (Segment::Rest) matches the remaining segments and may only appear as the final element;
  • {field.path=sub-template} (Segment::Variable) captures the portion of the path matched by its sub-template into a dotted message field; the shorthand {field} is {field=*} and nested variables are rejected;
  • a trailing :verb declares a custom method verb.

Extended grammar

PathTemplate::parse takes a Grammar argument. The default grammar is the strict google.api.http syntax above; passing a Grammar with Grammar::with_segment_affixes enabled additionally allows intra-segment prefix/suffix parameters: a single segment may wrap one {field.path} variable in literal text, for example /files/{name}.json, /v{version}/x, or /img-{id}.png. Such a segment parses to a Segment::Affix. The strict grammar rejects this syntax.

Examples

Parsing /shelves/{shelf}/books/{book=**}:archive yields four top-level Segments plus the custom verb archive:

use http_path_template::{Grammar, PathTemplate, Segment};

let template = PathTemplate::parse(
    "/shelves/{shelf}/books/{book=**}:archive",
    Grammar::default(),
)?;

assert_eq!(template.segments().len(), 4);
assert_eq!(template.verb(), Some("archive"));

assert_eq!(template.segments()[0], Segment::Literal("shelves"));
assert_eq!(template.segments()[2], Segment::Literal("books"));

let Segment::Variable(shelf) = template.segments()[1] else {
    panic!("expected variable")
};
assert_eq!(shelf.field_path(), "shelf");
assert!(shelf.segments().eq([Segment::Single]));

let Segment::Variable(book) = template.segments()[3] else {
    panic!("expected variable")
};
assert_eq!(book.field_path(), "book");
assert!(book.segments().eq([Segment::Rest]));

Crate features

  • std (default) — captures a std::backtrace::Backtrace into a ParseError for richer diagnostics. Disable (default-features = false) for #![no_std] use; the crate then requires only alloc and captures no backtrace. ParseError implements core::error::Error either way.

This crate was developed as part of The Oxidizer Project. Browse this crate's source code.