A fast, extensible, command-line arguments parser

Related tags

Parsing parkour
Overview

parkour

A fast, extensible, command-line arguments parser.

Documentation Crates.io Downloads License-MIT License-Apache Checks

Introduction 📚

The most popular argument parser, clap, allows you list all the possible arguments and their constraints, and then gives you a dynamic, stringly-typed object containing all the values. Usually these values are then manually extracted into structs and enums to access the values more conveniently and get the advantages of a static type system (example).

Parkour uses a different approach: Instead of parsing the arguments into an intermediate, stringly-typed object, it parses them directly into the types you want, so there's no cumbersome conversion. For types outside the standard library, you need to implement a trait, but in most cases this can be done with a simple derive macro.

This has several advantages:

  • It is very flexible: Every aspect of argument parsing can be tailored to your needs.
  • It is strongly typed: Many errors can be caught at compile time, so you waste less time debugging.
  • It is zero-cost: If you don't need a feature, you don't have to use it. Parkour should also be pretty fast, but don't take my word for it, benchmark it 😉

Status

Parkour started as an experiment and is very new (about 1 week old at the time of writing). Expect frequent breaking changes. If you like what you see, consider supporting this work by

  • Reading the docs
  • Trying it out
  • Giving feedback in this issue
  • Opening issues or sending PRs

Right now, parkour lacks some important features, which I intend to implement:

  • Auto-generated help messages
  • A DSL to write (sub)commands more ergonomically
  • More powerful derive macros
  • Error messages with ANSI colors

Example

use parkour::prelude::*;

#[derive(FromInputValue)]
enum ColorMode {
    Always,
    Auto,
    Never,
}

struct Command {
    color_mode: ColorMode,
    file: String,
}

impl FromInput<'static> for Command {
    type Context = ();

    fn from_input<P: Parse>(input: &mut P, _: &Self::Context)
        -> Result<Self, parkour::Error> {
        // discard the first argument
        input.bump_argument().unwrap();

        let mut file = None;
        let mut color_mode = None;

        while !input.is_empty() {
            if input.parse_long_flag("help") || input.parse_short_flag("h") {
                println!("Usage: run [-h,--help] [--color,-c auto|always|never] FILE");
                return Err(parkour::Error::early_exit());
            }
            if SetOnce(&mut color_mode)
                .apply(input, &Flag::LongShort("color", "c").into())? {
                continue;
            }
            if SetPositional(&mut file).apply(input, &"FILE")? {
                continue;
            }
            input.expect_empty()?;
        }

        Ok(Command {
            color_mode: color_mode.unwrap_or(ColorMode::Auto),
            file: file.ok_or_else(|| parkour::Error::missing_argument("FILE"))?,
        })
    }
}

In the future, I'd like to support a syntax like this:

use parkour::prelude::*;

#[derive(FromInput)]
#[parkour(main, help)]
#[arg(long = "version", short = "V", function = print_help)]
struct Command {
    #[parkour(default = ColorMode::Auto)]
    #[arg(long = "color", short = "c")]
    color_mode: ColorMode,

    #[arg(positional)]
    subcommand: Option<Subcommand>,
}

#[derive(FromInputValue)]
enum ColorMode {
    Always,
    Auto,
    Never,
}

#[derive(FromInput)]
enum Subcommand {
    Foo(Foo),
    Bar(Bar),
}

#[derive(FromInput)]
#[parkour(subcommand)]
struct Foo {
    #[parkour(default = 0, max = 3)]
    #[arg(long, short, action = Inc)]
    verbose: u8,

    #[arg(positional)]
    values: Vec<String>,
}

#[derive(FromInput)]
#[parkour(subcommand)]
struct Bar {
    #[parkour(default = false)]
    #[arg(long, short)]
    dry_run: bool,
}

fn print_version(_: &mut impl Parse) -> parkour::Result<()> {
    println!("command {}", env!("CARGO_PKG_VERSION"));
    Err(parkour::Error::early_exit())
}

Code of Conduct 🤝

Please be friendly and respectful to others. This should be a place where everyone can feel safe, therefore I intend to enforce the Rust code of conduct.

License

This project is licensed under either of

at your option.

You might also like...
A parser combinator library for Rust

combine An implementation of parser combinators for Rust, inspired by the Haskell library Parsec. As in Parsec the parsers are LL(1) by default but th

LR(1) parser generator for Rust

LALRPOP LALRPOP is a Rust parser generator framework with usability as its primary goal. You should be able to write compact, DRY, readable grammars.

The Elegant Parser

pest. The Elegant Parser pest is a general purpose parser written in Rust with a focus on accessibility, correctness, and performance. It uses parsing

A typed parser generator embedded in Rust code for Parsing Expression Grammars

Oak Compiled on the nightly channel of Rust. Use rustup for managing compiler channels. You can download and set up the exact same version of the comp

Rust query string parser with nesting support

What is Queryst? This is a fork of the original, with serde and serde_json updated to 0.9 A query string parsing library for Rust inspired by https://

Soon to be AsciiDoc parser implemented in rust!

pagliascii "But ASCII Doc, I am Pagliascii" Soon to be AsciiDoc parser implemented in rust! This project is the current implementation of the requeste

An LR parser generator, implemented as a proc macro

parsegen parsegen is an LR parser generator, similar to happy, ocamlyacc, and lalrpop. It currently generates canonical LR(1) parsers, but LALR(1) and

A rusty, dual-wielding Quake and Half-Life texture WAD parser.

Ogre   A rusty, dual-wielding Quake and Half-Life texture WAD parser ogre is a rust representation and nom parser for Quake and Half-Life WAD files. I

A modern dialogue executor and tree parser using YAML.

A modern dialogue executor and tree parser using YAML. This crate is for building(ex), importing/exporting(ex), and walking(ex) dialogue trees. convo

Owner
Ludwig Stecher
I'm studying computer science (B.Sc.) at the LMU in Munich. Rustacean. he/him
Ludwig Stecher
Extensible inline parser engine, the backend parsing engine for Lavendeux.

Lavendeux Parser - Extensible inline parser engine lavendeux-parser is an exensible parsing engine for mathematical expressions. It supports variable

Richard Carson 10 Nov 3, 2022
Minimalist pedantic command line parser

Lexopt Lexopt is an argument parser for Rust. It tries to have the simplest possible design that's still correct. It's so simple that it's a bit tedio

Jan Verbeek 155 Dec 28, 2022
Yet Another Parser library for Rust. A lightweight, dependency free, parser combinator inspired set of utility methods to help with parsing strings and slices.

Yap: Yet another (rust) parsing library A lightweight, dependency free, parser combinator inspired set of utility methods to help with parsing input.

James Wilson 117 Dec 14, 2022
Website for Microformats Rust parser (using 'microformats-parser'/'mf2')

Website for Microformats Rust parser (using 'microformats-parser'/'mf2')

Microformats 5 Jul 19, 2022
A fast monadic-style parser combinator designed to work on stable Rust.

Chomp Chomp is a fast monadic-style parser combinator library designed to work on stable Rust. It was written as the culmination of the experiments de

Martin Wernstål 228 Oct 31, 2022
Rust fast `&str` to `i64` parser (x86_64 SIMD, SSE4.1)

Rust fast &str to i64 parser (x86_64 SIMD, SSE4.1) Modified this version to support various string length and negative values. You need to define the

RoDmitry 4 Nov 1, 2022
A native Rust port of Google's robots.txt parser and matcher C++ library.

robotstxt A native Rust port of Google's robots.txt parser and matcher C++ library. Native Rust port, no third-part crate dependency Zero unsafe code

Folyd 72 Dec 11, 2022
Rust parser combinator framework

nom, eating data byte by byte nom is a parser combinators library written in Rust. Its goal is to provide tools to build safe parsers without compromi

Geoffroy Couprie 7.6k Jan 7, 2023
url parameter parser for rest filter inquiry

inquerest Inquerest can parse complex url query into a SQL abstract syntax tree. Example this url: /person?age=lt.42&(student=eq.true|gender=eq.'M')&

Jovansonlee Cesar 25 Nov 2, 2020
Parsing Expression Grammar (PEG) parser generator for Rust

Parsing Expression Grammars in Rust Documentation | Release Notes rust-peg is a simple yet flexible parser generator that makes it easy to write robus

Kevin Mehall 1.2k Dec 30, 2022