use thiserror::Error;
use super::sink::Full;
#[derive(Error, Debug, Clone, Copy, Eq, PartialEq)]
pub(crate) enum NodeError {
#[error("the {0} codec is disabled by its Cargo feature")]
Disabled(&'static str),
#[error("the {0} node is deprecated")]
Legacy(&'static str),
#[error("{0}")]
InvalidInput(&'static str),
#[error("{0}")]
InvalidParam(&'static str),
#[error("unsupported parameter: {0}")]
UnsupportedParam(&'static str),
#[error("output outcome out of range")]
OutcomeOutOfRange,
#[error("output created twice")]
OutputTwice,
#[error("a singleton output was not committed")]
OutputNotCommitted,
#[error("invalid codec header")]
Header,
#[cfg(feature = "zstd")]
#[error("{0} backend failure")]
Backend(&'static str),
}
#[derive(Error, Debug, Clone, Eq, PartialEq)]
pub(crate) enum ExecError {
#[error("node {node} failed: {source}")]
Node {
node: &'static str,
#[source]
source: NodeError,
},
#[error("node {0} received an unexpected number of inputs")]
NodeInputCount(&'static str),
#[error("node {0} received an input of the wrong type")]
NodeInputType(&'static str),
#[error("node {0} is not available at this format version")]
NodeVersion(&'static str),
#[error("invalid graph")]
GraphInvalid,
#[error("invalid node")]
NodeInvalid,
#[error("a successor received an unexpected number of inputs")]
SuccessorInputs,
#[error("an edge already has a successor")]
SuccessorAlreadySet,
#[error("an edge has no successor")]
SuccessorMissing,
#[error("graph depth limit exceeded")]
DepthExceeded,
#[error("a segmenter can only run on the full input")]
SegmenterPlacement,
#[error("segmenters do not convert their inputs")]
SegmenterConversion,
#[error("a segmenter must produce at least one chunk")]
SegmenterNoChunks,
#[error("a segmenter must consume its whole input")]
SegmenterNotConsumed,
#[error("{0}")]
Parameter(&'static str),
#[error("no implicit conversion between the stream types")]
NoConversion,
#[error("{0} exceeds the format limit")]
Limit(&'static str),
#[error("the destination is full")]
Full,
#[cfg(any(
test,
not(all(
feature = "field-lz",
feature = "lz",
feature = "entropy",
feature = "partition",
feature = "merge-sorted"
))
))]
#[error("the graph's codec is disabled by its Cargo feature")]
Unported,
#[error("{0}")]
User(&'static str),
}
impl From<Full> for ExecError {
fn from(_: Full) -> Self {
Self::Full
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::ToString;
use core::error::Error;
#[test]
fn messages_and_sources_describe_the_failure() {
let error = ExecError::Node {
node: "zstd",
source: NodeError::Disabled("zstd"),
};
assert!(error.to_string().contains("zstd failed"));
assert_eq!(
error.source().map(ToString::to_string).as_deref(),
Some("the zstd codec is disabled by its Cargo feature")
);
assert_eq!(ExecError::from(Full), ExecError::Full);
let messages = [
NodeError::Disabled("lz").to_string(),
NodeError::Legacy("rolz").to_string(),
NodeError::UnsupportedParam("x").to_string(),
NodeError::OutcomeOutOfRange.to_string(),
NodeError::OutputTwice.to_string(),
NodeError::OutputNotCommitted.to_string(),
NodeError::Header.to_string(),
#[cfg(feature = "zstd")]
NodeError::Backend("zstd").to_string(),
NodeError::InvalidInput("in").to_string(),
NodeError::InvalidParam("p").to_string(),
];
assert!(messages.iter().all(|message| !message.is_empty()));
let errors = [
ExecError::NodeInputCount("n"),
ExecError::NodeInputType("n"),
ExecError::NodeVersion("n"),
ExecError::GraphInvalid,
ExecError::NodeInvalid,
ExecError::SuccessorInputs,
ExecError::SuccessorAlreadySet,
ExecError::SuccessorMissing,
ExecError::DepthExceeded,
ExecError::SegmenterPlacement,
ExecError::SegmenterConversion,
ExecError::SegmenterNoChunks,
ExecError::SegmenterNotConsumed,
ExecError::Parameter("p"),
ExecError::NoConversion,
ExecError::Limit("nodes"),
ExecError::Full,
ExecError::User("u"),
ExecError::Unported,
];
assert!(errors.iter().all(|error| !error.to_string().is_empty()));
}
}