pmpx_plugin/verb.rs
1//! The verbs a plugin is asked to translate.
2//!
3//! A closed set -- this is all the command line has -- and their numbering is part of the ABI, so
4//! it is pinned against [`crate::abi`] rather than chosen here.
5
6use std::fmt;
7use std::str::FromStr;
8
9use crate::abi;
10use crate::PluginError;
11
12/// The verbs pmpx recognizes. A closed set -- this is all the command line has.
13/// The numbers correspond one-to-one with the `VERB_*` constants in [`abi`], and the order must
14/// not change (changing it requires [`abi::ABI_VERSION`] + 1); a test in the `abi` module pins
15/// this down.
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
17#[repr(u32)]
18pub enum Verb {
19 /// Install dependencies. No argument = install everything in the lockfile, with arguments =
20 /// add.
21 Install = abi::VERB_INSTALL,
22 /// Remove dependencies.
23 Remove = abi::VERB_REMOVE,
24 /// Run a script / target.
25 Run = abi::VERB_RUN,
26 /// Build.
27 Build = abi::VERB_BUILD,
28 /// Test.
29 Test = abi::VERB_TEST,
30 /// Update dependencies.
31 Update = abi::VERB_UPDATE,
32 /// Escape hatch: run an arbitrary command. Plugins that do not support it should report an
33 /// error explicitly, see [`PackageManager::command`](crate::PackageManager::command).
34 Exec = abi::VERB_EXEC,
35}
36
37impl Verb {
38 /// All verbs, in numbering order.
39 pub const ALL: &'static [Verb] = &[
40 Verb::Install,
41 Verb::Remove,
42 Verb::Run,
43 Verb::Build,
44 Verb::Test,
45 Verb::Update,
46 Verb::Exec,
47 ];
48
49 /// Convert to the number used across the boundary.
50 pub const fn to_abi(self) -> u32 {
51 self as u32
52 }
53
54 /// Reconstruct from a cross-boundary number; returns `None` for an unknown one (this is where
55 /// a host and a plugin of mismatched versions land).
56 pub const fn from_abi(n: u32) -> Option<Verb> {
57 match n {
58 abi::VERB_INSTALL => Some(Verb::Install),
59 abi::VERB_REMOVE => Some(Verb::Remove),
60 abi::VERB_RUN => Some(Verb::Run),
61 abi::VERB_BUILD => Some(Verb::Build),
62 abi::VERB_TEST => Some(Verb::Test),
63 abi::VERB_UPDATE => Some(Verb::Update),
64 abi::VERB_EXEC => Some(Verb::Exec),
65 _ => None,
66 }
67 }
68
69 /// The word written on the command line.
70 pub const fn as_str(self) -> &'static str {
71 match self {
72 Verb::Install => "install",
73 Verb::Remove => "remove",
74 Verb::Run => "run",
75 Verb::Build => "build",
76 Verb::Test => "test",
77 Verb::Update => "update",
78 Verb::Exec => "exec",
79 }
80 }
81}
82
83impl fmt::Display for Verb {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 f.write_str(self.as_str())
86 }
87}
88
89impl FromStr for Verb {
90 type Err = PluginError;
91
92 fn from_str(s: &str) -> Result<Self, Self::Err> {
93 Verb::ALL
94 .iter()
95 .copied()
96 .find(|v| v.as_str() == s)
97 .ok_or_else(|| PluginError::other(format!("unknown verb: {s}")))
98 }
99}