Wado
<!-- Auto-generated by: wado doc -f markdown core:args --> <!-- Do not edit this file directly. -->

core:args

Command-line argument parsing (WEP wep-2026-06-22-core-args.md).

core:args is a non-self-describing, parse-only Deserializer over argv, peer to core:json_nsd. Argument types are ordinary structs with impl Deserialize for T; — no bespoke derive. Struct fields become --long options; fields marked #[serde(positional)] are filled from bare tokens in declaration order. Scalar tokens are converted with LenientFromStr.

Supported: --name value, --name=value, bool flags (--name), Option<T> = null, required/optional/variadic positionals, repeatable List<T> options (--inc a --inc b, interspersing allowed), and the -- end-of-options marker. -/_ fold, so --dry-run binds dry_run.

Long options only: an option value never starts with --, so a missing value (--name --next) is reported as MissingValue rather than swallowing the next flag; a single - is a value, so negatives like -5 work. A repeatable option always takes a value (there is no repeatable flag); --flag with no value is MissingValue.

Subcommands are a #[serde(positional)] field whose type is a variant: the leading bare token selects the case (externally tagged) and the rest is the payload, so command [global-opts] subcommand [sub-opts] works and nesting is free. The tag matches the case's wire name; keep the cases idiomatic PascalCase and apply #[serde(rename_all = "kebab-case")] (or rename per case) for lowercase/kebab subcommands like add-remote.

Positional declaration order is not validated

Positional fields are bound left-to-right by declaration order (rank), and that binding is greedy. core:args does not check the schema for well-formedness, so a few declarations parse in surprising ways — keep these invariants yourself (the compiler will not flag a violation; you get a confusing MissingArgument, not a crash):

Validation is intentionally omitted: it is a CLI-specific well-formedness rule, not a data-model property, so it stays out of the format-agnostic compiler layer; and at parse time the deserializer sees only field indices, not their types or arity, so it cannot self-check (only over-supply — "too many positionals" — is caught). See the WEP for the rationale.

Synopsis

struct Options {
    #[serde(positional)]
    input: String,
    verbose: bool = false,
    jobs: i32 = 1,
}
impl Deserialize for Options;

assert parse::<Options>(["in.txt", "--verbose", "--jobs", "4"]) matches { Ok(opts) && opts.input == "in.txt"
    && opts.verbose
    && opts.jobs == 4 };

Functions

pub fn parse<T: Deserialize>(argv: List<String>) -> Result<T, ArgsError>

Parse argv (excluding the program name) into T. Effect-free and testable; subcommand dispatch and tests inject a List<String> directly.

pub fn from_env<T: Deserialize>() -> Result<T, ArgsError> with Environment

Parse the process arguments (from core:cli::args(), with the program name dropped) into T.

Structs

pub struct ArgsError

A command-line parse failure.

kind: ArgsErrorKind

message: String

pub struct ArgvDeserializer

The argv Deserializer. Holds the token stream and the plumbing that serves the current field's value to the deserialize_* methods.

Fields are private.

impl Deserializer for ArgvDeserializer

fn deserialize_i32(&mut self) -> Result<i32, DeserializeError>
fn deserialize_i64(&mut self) -> Result<i64, DeserializeError>
fn deserialize_u32(&mut self) -> Result<u32, DeserializeError>
fn deserialize_u64(&mut self) -> Result<u64, DeserializeError>
fn deserialize_i128(&mut self) -> Result<i128, DeserializeError>
fn deserialize_u128(&mut self) -> Result<u128, DeserializeError>
fn deserialize_f32(&mut self) -> Result<f32, DeserializeError>
fn deserialize_f64(&mut self) -> Result<f64, DeserializeError>
fn deserialize_bool(&mut self) -> Result<bool, DeserializeError>
fn deserialize_char(&mut self) -> Result<char, DeserializeError>
fn deserialize_string(&mut self) -> Result<String, DeserializeError>
fn is_null(&mut self) -> Result<bool, DeserializeError>
fn begin_seq(&mut self) -> Result<ArgvSeqAccess, DeserializeError> with stores[self]
fn begin_map(&mut self) -> Result<ArgvMapAccess, DeserializeError> with stores[self]
fn begin_struct(&mut self, name: &String, num_fields: i32) -> Result<ArgvStructAccess, DeserializeError> with stores[self]
fn begin_variant(&mut self, type_name: &String, num_cases: i32) -> Result<ArgvVariantAccess, DeserializeError> with stores[self]
fn deserialize_any<V: Visitor>(&mut self, visitor: &mut V) -> Result<V::Value, DeserializeError>

Enums

pub enum ArgsErrorKind

Error categories surfaced by core:args.

UnknownOption

MissingValue

MissingArgument

UnknownSubcommand

InvalidValue

TooManyPositionals