Skip to main content

pmpx_plugin/
error.rs

1//! The three errors a plugin can report.
2//!
3//! Deliberately only three: that is what the host needs to distinguish -- the verb is not
4//! supported (so it can degrade to passing through verbatim), the arguments are wrong, and
5//! everything else. The human-readable description travels in the payload.
6
7use std::fmt;
8
9use crate::abi;
10use crate::Verb;
11
12/// The errors a plugin can report.
13/// Deliberately only three -- because the host only needs to distinguish three: the verb is not
14/// supported (so it can degrade to passing through verbatim), the arguments are wrong, and
15/// everything else. The human-readable description goes in the payload and the host prints it to
16/// stderr as-is.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub enum PluginError {
19    /// This backend does not support that verb. For `pmpx exec` the host degrades to passing
20    /// through verbatim.
21    UnsupportedVerb(Verb),
22
23    /// Invalid arguments.
24    InvalidArgs(String),
25
26    /// Anything else. Includes a plugin panic -- the host only needs to know "it blew up".
27    Other(String),
28}
29
30impl PluginError {
31    /// Construct "unsupported verb".
32    pub fn unsupported_verb(verb: Verb) -> Self {
33        PluginError::UnsupportedVerb(verb)
34    }
35
36    /// Construct "invalid arguments".
37    pub fn invalid_args(message: impl Into<String>) -> Self {
38        PluginError::InvalidArgs(message.into())
39    }
40
41    /// Construct some other error.
42    pub fn other(message: impl Into<String>) -> Self {
43        PluginError::Other(message.into())
44    }
45
46    /// The corresponding cross-boundary error code.
47    pub fn code(&self) -> u32 {
48        match self {
49            PluginError::UnsupportedVerb(_) => abi::PMPX_ERR_UNSUPPORTED_VERB,
50            PluginError::InvalidArgs(_) => abi::PMPX_ERR_INVALID_ARGS,
51            PluginError::Other(_) => abi::PMPX_ERR_INTERNAL,
52        }
53    }
54
55    /// Human-readable description.
56    pub fn message(&self) -> String {
57        match self {
58            PluginError::UnsupportedVerb(v) => format!("unsupported verb {v}"),
59            PluginError::InvalidArgs(m) => m.clone(),
60            PluginError::Other(m) => m.clone(),
61        }
62    }
63}
64
65impl fmt::Display for PluginError {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        f.write_str(&self.message())
68    }
69}
70
71// Hand-written rather than thiserror: this crate is deliberately dependency-free, and all `Error`
72// needs is the line below.
73impl std::error::Error for PluginError {}
74
75impl From<String> for PluginError {
76    fn from(message: String) -> Self {
77        PluginError::Other(message)
78    }
79}
80
81impl From<&str> for PluginError {
82    fn from(message: &str) -> Self {
83        PluginError::Other(message.to_string())
84    }
85}
86
87impl From<std::io::Error> for PluginError {
88    fn from(e: std::io::Error) -> Self {
89        PluginError::Other(e.to_string())
90    }
91}