winnow_args/run.rs
1//! Running the command a line selected.
2//!
3//! Parsing gives a tree of types: a struct of the program's flags, holding an
4//! enum of its subcommands, each holding a struct of its own. What the
5//! program does next is nearly always the same: find the variant that was
6//! selected and call the code that carries it out. [`Run`] is that call, and
7//! `#[arg(run)]` on a `Subcommand` enum writes the `match` that makes it.
8//!
9//! Each command implements the trait, in a file of its own if it likes:
10//!
11#![cfg_attr(feature = "derive", doc = "```")]
12#![cfg_attr(not(feature = "derive"), doc = "```ignore")]
13//! use winnow_args::run::Run;
14//! use winnow_args::{Args, Subcommand};
15//!
16//! #[derive(Args)]
17//! struct Cli {
18//! #[arg(short, long, global)]
19//! verbose: bool,
20//! #[arg(subcommand)]
21//! command: Command,
22//! }
23//!
24//! #[derive(Subcommand)]
25//! #[arg(run)]
26//! enum Command {
27//! Add(Add),
28//! Remove(Remove),
29//! }
30//!
31//! #[derive(Args)]
32//! struct Add {
33//! #[arg(positional)]
34//! name: String,
35//! }
36//!
37//! #[derive(Args)]
38//! struct Remove {
39//! #[arg(positional)]
40//! name: String,
41//! }
42//!
43//! /// What every command is handed: here, the flags of the program.
44//! struct Context {
45//! verbose: bool,
46//! }
47//!
48//! impl Run<&Context> for Add {
49//! type Output = String;
50//!
51//! fn run(self, context: &Context) -> String {
52//! match context.verbose {
53//! true => format!("adding {}, at length", self.name),
54//! false => format!("adding {}", self.name),
55//! }
56//! }
57//! }
58//!
59//! impl Run<&Context> for Remove {
60//! type Output = String;
61//!
62//! fn run(self, _: &Context) -> String {
63//! format!("removing {}", self.name)
64//! }
65//! }
66//!
67//! let cli = Cli::parse_from(["-v", "add", "x"])?;
68//! let context = Context { verbose: cli.verbose };
69//! assert_eq!(cli.command.run(&context), "adding x, at length");
70//! # Ok::<(), winnow_args::Error>(())
71//! ```
72//!
73//! The context is whatever the commands share: a reference to the parsed
74//! program, a connection, nothing at all (`()`, the default). The enum
75//! implements the trait for every context all of its commands take, so a
76//! struct that holds a nested enum of subcommands implements it by calling
77//! `self.command.run(context)`, and the nesting runs all the way down.
78//!
79//! [`RunAsync`] and `#[arg(run_async)]` are the same for commands that are
80//! awaited.
81//!
82//! None of this is on the path of a parse: it is a `match` in the program,
83//! written by the derive rather than by hand.
84
85/// A command that can be carried out, given `C`.
86pub trait Run<C = ()> {
87 /// What running the command produces.
88 type Output;
89
90 /// Carry out the command.
91 fn run(self, context: C) -> Self::Output;
92}
93
94/// A command that is awaited: [`Run`], as a future.
95///
96/// An implementation writes `async fn run_async(self, context: C)`. The
97/// signature here is `-> impl Future` so that the trait implies no `Send`
98/// bound either way: whether a command's future is `Send` is decided by what
99/// the command does.
100pub trait RunAsync<C = ()> {
101 /// What running the command produces, once awaited.
102 type Output;
103
104 /// Carry out the command.
105 fn run_async(self, context: C) -> impl core::future::Future<Output = Self::Output>;
106}