Crate serde_args

Source
Expand description

Command line argument parsing with serde.

This library allows parsing command line arguments into types implementing Deserialize. Included are all of the typical features you’d find in an command line argument parsing library, including help generation, help customization, version support, and flexible parsing options.

Unlike other argument parsing libraries, serde_args uses serde’s traits to define the command line interface. No builder or derive interface is provided; instead, any object implementing Deserialize can be used. This means that you can use serde’s own derive macros (that you are likely already familiar with) or implement the Deserialize trait by hand to define your command line interface.

serde_args defines an unambiguous deserialization format through internal Deserializers; therefore it should be noted that not every command line interface can be represented using it. Notably, optional positional parameters are not supported at all, nor are default command values. The format defined here requires that all positional arguments (those without a - or -- preceeding them) be required arguments, and that all other arguments be preceeded with either a - or -- (including compound types). See the format specification for more details.

§Parsing Arguments

To use serde_args for your own command line argument parsing, you must first define a type implementing serde’s Deserialize trait. This can be done using serde’s derive macro or by implementing the trait by hand. For example, a simple program could be defined as:

use serde::Deserialize;
use std::path::PathBuf;

#[derive(Deserialize)]
#[serde(expecting = "An example program")]
struct Args {
    path: PathBuf,
    #[serde(alias = "f")]
    force: bool,
}

fn main() {
    let args: Args = match serde_args::from_env() {
        Ok(args) => args,
        Err(error) => {
            println!("{error}");
            return;
        }
    };
    // Execute your program with `args`...
}

Command-based interfaces can be defined using enums:

use serde::Deserialize;
use std::path::PathBuf;

#[derive(Deserialize)]
#[serde(expecting = "A command-based interface")]
#[serde(rename_all = "kebab-case")]
enum Command {
    Add {
        path: PathBuf,
    },
    Commit {
        #[serde(alias = "m")]
        message: Option<String>,
    },
    Push {
        #[serde(alias = "f")]
        force: bool,
    },
}

fn main() {
    let command: Command = match serde_args::from_env() {
        Ok(command) => command,
        Err(error) => {
            println!("{error}");
            return;
        }
    };
    // Execute your program with `command`...
}

For simple use cases you can also use existing types that already implement Deserialize:

fn main() {
    let value: String = match serde_args::from_env() {
        Ok(value) => value,
        Err(error) => {
            println!("{error}");
            return;
        }
    };
    // Execute your program with `value`...
}

Note that the only way to deserialize using this crate is through from_env() and from_env_seed(). No public Deserializer is provided.

§Error Formatting

On failure, from_env() will return an Error. This will occur when the provided type is incompatible with this crate (see Supported serde Attributes for common reasons why types are not compatible), when the user has input command line arguments that cannot be parsed into the provided type, or when the user requests the generated help message (either through the --help flag or by providing no arguments). In any case, the returned Error implements the Display trait and is able to be printed and displayed to the user.

For example, a program taking a single unsigned integer value as a parameter would print an error that occurred like so:

if let Err(error) = serde_args::from_env::<usize>() {
    println!("{error}");
}

To print an error that is formatted with ANSI color sequences, use the “alternate” form of printing with the # flag:

if let Err(error) = serde_args::from_env::<usize>() {
    println!("{error:#}");
}

§Customization

serde_args allows for customizing in the form of messages to be displayed in help output and the displaying of version information. These are most easily customized using the #[generate] attribute (requires the macros feature). This macro must be combined with serde's Deserialize` derive macro.

§Custom Help Messages

Descriptions for each of your fields or variants can be automatically imported from your struct or enum’s doc comment using #[generate] with doc_help as a parameter:

use serde::Deserialize;
use std::path::PathBuf;

/// An example program.
#[serde_args::generate(doc_help)]
#[derive(Deserialize)]
struct Args {
    /// The path to operate on.
    path: PathBuf,
    /// Whether the program's behavior should be forced.
    #[serde(alias = "f")]
    force: bool,
}

fn main() {
    let args: Args = match serde_args::from_env() {
        Ok(args) => args,
        Err(error) => {
            println!("{error}");
            return;
        }
    };
    // Execute your program with `args`...
}

§Version Information

To automatically make the version of your crate available through a --version flag, use #[generate] with version as a parameter:

use serde::Deserialize;

#[serde_args::generate(version)]
#[derive(Deserialize)]
struct Args {
    foo: String,
    bar: bool,
}

fn main() {
    let args: Args = match serde_args::from_env() {
        Ok(args) => args,
        Err(error) => {
            println!("{error}");
            return;
        }
    };
    // Execute your program with `args`...
}

§Customization Without Deriving

To provide these customization options without deriving, see expecting() Option Specification.

§Supported serde Attributes

Nearly all serde attributes are supported. Those that are not supported are those that require a self-describing deserializer (the format defined by serde_args is not self-describing). Specifically, the following attributes will not work:

Aside from the above list, all other attributes are supported. Some attributes are especially useful for defining command line interfaces, including:

  • #[serde(alias)] - Useful for defining multiple names for optional fields or command variants.
  • #[serde(expecting)] - Can be used to define a description for your program. Whatever is provided here will be output at the top of the generated help message.
  • #[serde(rename_all)] - Useful for renaming all field names or enum variants to kebab-case, which is common for command-line tools.

Modules§

specification
A full specification of the format defined by serde_args.

Structs§

Error
An error encountered during deserialization.

Functions§

from_env
Deserialize from env::args().
from_env_seed
Deserialize from env::args() using a seed.

Attribute Macros§

generatemacros
Add on for #[derive(Deserialize)] to add serde_args-specific information.