Skip to main content

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}