Skip to main content

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}