use super::TransformError;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ErrorClass {
InvalidOptions,
InvalidInput,
DecodeFailed,
UnsupportedInputMediaType,
UnsupportedOutputMediaType,
EncodeFailed,
CapabilityMissing,
LimitExceeded,
InvalidRequest,
UnsupportedMediaType,
Unauthorized,
Forbidden,
NotFound,
NotAcceptable,
RequestTimeout,
PayloadTooLarge,
UnprocessableEntity,
TooManyRequests,
InternalError,
NotImplemented,
BadGateway,
ServiceUnavailable,
LoopDetected,
}
impl ErrorClass {
#[allow(dead_code)]
pub(crate) const fn slug(self) -> &'static str {
match self {
Self::InvalidOptions => "invalid-options",
Self::InvalidInput => "invalid-input",
Self::DecodeFailed => "decode-failed",
Self::UnsupportedInputMediaType => "unsupported-input-media-type",
Self::UnsupportedOutputMediaType => "unsupported-output-media-type",
Self::EncodeFailed => "encode-failed",
Self::CapabilityMissing => "capability-missing",
Self::LimitExceeded => "limit-exceeded",
Self::InvalidRequest => "invalid-request",
Self::UnsupportedMediaType => "unsupported-media-type",
Self::Unauthorized => "unauthorized",
Self::Forbidden => "forbidden",
Self::NotFound => "not-found",
Self::NotAcceptable => "not-acceptable",
Self::RequestTimeout => "request-timeout",
Self::PayloadTooLarge => "payload-too-large",
Self::UnprocessableEntity => "unprocessable-entity",
Self::TooManyRequests => "too-many-requests",
Self::InternalError => "internal-error",
Self::NotImplemented => "not-implemented",
Self::BadGateway => "bad-gateway",
Self::ServiceUnavailable => "service-unavailable",
Self::LoopDetected => "loop-detected",
}
}
#[cfg(any(feature = "wasm", test))]
pub(crate) const fn camel_case_name(self) -> &'static str {
match self {
Self::InvalidOptions => "invalidOptions",
Self::InvalidInput => "invalidInput",
Self::DecodeFailed => "decodeFailed",
Self::UnsupportedInputMediaType => "unsupportedInputMediaType",
Self::UnsupportedOutputMediaType => "unsupportedOutputMediaType",
Self::EncodeFailed => "encodeFailed",
Self::CapabilityMissing => "capabilityMissing",
Self::LimitExceeded => "limitExceeded",
Self::InvalidRequest => "invalidRequest",
Self::UnsupportedMediaType => "unsupportedMediaType",
Self::Unauthorized => "unauthorized",
Self::Forbidden => "forbidden",
Self::NotFound => "notFound",
Self::NotAcceptable => "notAcceptable",
Self::RequestTimeout => "requestTimeout",
Self::PayloadTooLarge => "payloadTooLarge",
Self::UnprocessableEntity => "unprocessableEntity",
Self::TooManyRequests => "tooManyRequests",
Self::InternalError => "internalError",
Self::NotImplemented => "notImplemented",
Self::BadGateway => "badGateway",
Self::ServiceUnavailable => "serviceUnavailable",
Self::LoopDetected => "loopDetected",
}
}
#[cfg(test)]
pub(crate) const ALL: [Self; 23] = [
Self::InvalidOptions,
Self::InvalidInput,
Self::DecodeFailed,
Self::UnsupportedInputMediaType,
Self::UnsupportedOutputMediaType,
Self::EncodeFailed,
Self::CapabilityMissing,
Self::LimitExceeded,
Self::InvalidRequest,
Self::UnsupportedMediaType,
Self::Unauthorized,
Self::Forbidden,
Self::NotFound,
Self::NotAcceptable,
Self::RequestTimeout,
Self::PayloadTooLarge,
Self::UnprocessableEntity,
Self::TooManyRequests,
Self::InternalError,
Self::NotImplemented,
Self::BadGateway,
Self::ServiceUnavailable,
Self::LoopDetected,
];
}
impl TransformError {
pub(crate) const fn class(&self) -> ErrorClass {
match self {
Self::InvalidOptions(_) => ErrorClass::InvalidOptions,
Self::InvalidInput(_) => ErrorClass::InvalidInput,
Self::DecodeFailed(_) => ErrorClass::DecodeFailed,
Self::UnsupportedInputMediaType(_) => ErrorClass::UnsupportedInputMediaType,
Self::UnsupportedOutputMediaType(_) => ErrorClass::UnsupportedOutputMediaType,
Self::EncodeFailed(_) => ErrorClass::EncodeFailed,
Self::CapabilityMissing(_) => ErrorClass::CapabilityMissing,
Self::LimitExceeded(_) => ErrorClass::LimitExceeded,
}
}
}
#[cfg(test)]
mod tests {
use super::{ErrorClass, TransformError};
use crate::MediaType;
fn camel_case(slug: &str) -> String {
let mut out = String::with_capacity(slug.len());
let mut capitalize = false;
for ch in slug.chars() {
if ch == '-' {
capitalize = true;
} else if capitalize {
out.extend(ch.to_uppercase());
capitalize = false;
} else {
out.push(ch);
}
}
out
}
#[test]
fn camel_case_name_matches_slug() {
for class in ErrorClass::ALL {
assert_eq!(
class.camel_case_name(),
camel_case(class.slug()),
"{class:?} spells its slug and its camelCase name differently"
);
}
}
#[test]
fn slugs_are_unique_and_kebab_case() {
let mut seen: Vec<&str> = Vec::new();
for class in ErrorClass::ALL {
let slug = class.slug();
assert!(!seen.contains(&slug), "{slug} is used by two classes");
assert!(
slug.chars().all(|c| c.is_ascii_lowercase() || c == '-'),
"{slug} is not kebab case"
);
seen.push(slug);
}
}
#[test]
fn transform_errors_carry_their_documented_class() {
let cases: [(TransformError, &str); 8] = [
(
TransformError::InvalidOptions("x".into()),
"invalid-options",
),
(TransformError::InvalidInput("x".into()), "invalid-input"),
(TransformError::DecodeFailed("x".into()), "decode-failed"),
(
TransformError::UnsupportedInputMediaType("x".into()),
"unsupported-input-media-type",
),
(
TransformError::UnsupportedOutputMediaType(MediaType::Gif),
"unsupported-output-media-type",
),
(TransformError::EncodeFailed("x".into()), "encode-failed"),
(
TransformError::CapabilityMissing("x".into()),
"capability-missing",
),
(TransformError::LimitExceeded("x".into()), "limit-exceeded"),
];
for (error, slug) in cases {
assert_eq!(error.class().slug(), slug, "{error:?}");
}
}
}