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