use std::fmt;
#[derive(Debug)]
pub enum LoadError {
ContainerTooNew { found: u32, supported: u32 },
UnsupportedFeatures { missing: Vec<String> },
CorruptManifest { reason: String },
UnknownTypeId { kind: &'static str, id: String },
Io(std::io::Error),
Zip(String),
Json(String),
}
impl fmt::Display for LoadError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LoadError::ContainerTooNew { found, supported } => write!(
f,
"container version {found} is newer than supported version {supported}; \
please update Darkly to open this file"
),
LoadError::UnsupportedFeatures { missing } => write!(
f,
"this file needs features your build doesn't support: {}; \
please update Darkly to open this file",
missing.join(", ")
),
LoadError::CorruptManifest { reason } => write!(f, "corrupt manifest: {reason}"),
LoadError::UnknownTypeId { kind, id } => {
write!(f, "unknown {kind} type id: {id}")
}
LoadError::Io(e) => write!(f, "io error: {e}"),
LoadError::Zip(e) => write!(f, "zip error: {e}"),
LoadError::Json(e) => write!(f, "manifest json error: {e}"),
}
}
}
impl std::error::Error for LoadError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
LoadError::Io(e) => Some(e),
_ => None,
}
}
}
impl From<std::io::Error> for LoadError {
fn from(e: std::io::Error) -> Self {
LoadError::Io(e)
}
}
impl From<serde_json::Error> for LoadError {
fn from(e: serde_json::Error) -> Self {
LoadError::Json(e.to_string())
}
}
impl LoadError {
pub fn to_json(&self) -> serde_json::Value {
use serde_json::json;
match self {
LoadError::ContainerTooNew { found, supported } => json!({
"kind": "containerTooNew",
"found": found,
"supported": supported,
"message": self.to_string(),
}),
LoadError::UnsupportedFeatures { missing } => json!({
"kind": "unsupportedFeatures",
"missing": missing,
"message": self.to_string(),
}),
LoadError::CorruptManifest { reason } => json!({
"kind": "corruptManifest",
"reason": reason,
"message": self.to_string(),
}),
LoadError::UnknownTypeId { kind, id } => json!({
"kind": "unknownTypeId",
"registry": kind,
"id": id,
"message": self.to_string(),
}),
LoadError::Io(e) => json!({
"kind": "io",
"message": e.to_string(),
}),
LoadError::Zip(msg) => json!({
"kind": "zip",
"message": msg,
}),
LoadError::Json(msg) => json!({
"kind": "json",
"message": msg,
}),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn display_includes_diagnostic_for_unsupported_features() {
let err = LoadError::UnsupportedFeatures {
missing: vec!["veil/lens_flare".into(), "blend_mode/divide".into()],
};
let msg = format!("{err}");
assert!(msg.contains("veil/lens_flare"));
assert!(msg.contains("blend_mode/divide"));
assert!(msg.contains("update Darkly"));
}
#[test]
fn display_includes_versions_for_container_too_new() {
let err = LoadError::ContainerTooNew {
found: 999,
supported: 1,
};
let msg = format!("{err}");
assert!(msg.contains("999"));
assert!(msg.contains("supported version 1"));
}
}