mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Rework handling of esplugin errors
The error scenario represented by PluginNotLoadedError is distinguished from all other esplugin errors by LOOT, so it's worth handling separately.
This commit is contained in:
@@ -1,50 +0,0 @@
|
||||
// Unless otherwise noted, these constants and the mapping logic are copied from
|
||||
// esplugin-ffi.
|
||||
|
||||
use std::ffi::c_int;
|
||||
|
||||
use esplugin::Error;
|
||||
|
||||
const ESP_ERROR_PARSE_ERROR: c_int = 5;
|
||||
|
||||
const ESP_ERROR_NO_FILENAME: c_int = 7;
|
||||
|
||||
const ESP_ERROR_TEXT_DECODE_ERROR: c_int = 8;
|
||||
|
||||
const ESP_ERROR_IO_ERROR: c_int = 10;
|
||||
|
||||
const ESP_ERROR_FILE_NOT_FOUND: c_int = 11;
|
||||
|
||||
const ESP_ERROR_IO_PERMISSION_DENIED: c_int = 12;
|
||||
|
||||
const ESP_ERROR_UNRESOLVED_RECORD_IDS: c_int = 13;
|
||||
|
||||
const ESP_ERROR_PLUGIN_METADATA_NOT_FOUND: c_int = 14;
|
||||
|
||||
// This constant is not copied from esplugin-ffi, but does not conflict with any
|
||||
// values defined there.
|
||||
pub(crate) const ESP_ERROR_UNKNOWN: c_int = c_int::MAX;
|
||||
|
||||
#[expect(
|
||||
clippy::wildcard_enum_match_arm,
|
||||
reason = "It doesn't matter if other I/O error kinds are added in the future"
|
||||
)]
|
||||
fn map_io_error(err: &std::io::Error) -> c_int {
|
||||
match err.kind() {
|
||||
std::io::ErrorKind::NotFound => ESP_ERROR_FILE_NOT_FOUND,
|
||||
std::io::ErrorKind::PermissionDenied => ESP_ERROR_IO_PERMISSION_DENIED,
|
||||
_ => ESP_ERROR_IO_ERROR,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub(crate) fn map_error(err: &Error) -> c_int {
|
||||
match err {
|
||||
Error::IoError(x) => map_io_error(x),
|
||||
Error::NoFilename(_) => ESP_ERROR_NO_FILENAME,
|
||||
Error::ParsingIncomplete(_) | Error::ParsingError(_, _) => ESP_ERROR_PARSE_ERROR,
|
||||
Error::DecodeError(_) => ESP_ERROR_TEXT_DECODE_ERROR,
|
||||
Error::UnresolvedRecordIds(_) => ESP_ERROR_UNRESOLVED_RECORD_IDS,
|
||||
Error::PluginMetadataNotFound(_) => ESP_ERROR_PLUGIN_METADATA_NOT_FOUND,
|
||||
}
|
||||
}
|
||||
@@ -92,100 +92,6 @@
|
||||
clippy::verbose_file_reads,
|
||||
clippy::wildcard_enum_match_arm
|
||||
)]
|
||||
use std::{error::Error, ffi::c_int};
|
||||
|
||||
use libloot::error::PluginDataError;
|
||||
|
||||
mod esplugin;
|
||||
|
||||
// It's important for API stability that these variants' values don't change.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[repr(u8)]
|
||||
#[non_exhaustive]
|
||||
pub enum SystemErrorCategory {
|
||||
Esplugin = 1,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SystemErrorCategory {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
SystemErrorCategory::Esplugin => write!(f, "esplugin"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SystemError {
|
||||
code: c_int,
|
||||
category: SystemErrorCategory,
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl SystemError {
|
||||
#[must_use]
|
||||
pub fn code(&self) -> c_int {
|
||||
self.code
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn category(&self) -> SystemErrorCategory {
|
||||
self.category
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn message(&self) -> &str {
|
||||
&self.message
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SystemError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{} error, code {}: {}",
|
||||
self.category, self.code, self.message
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for SystemError {}
|
||||
|
||||
impl From<PluginDataError> for SystemError {
|
||||
fn from(value: PluginDataError) -> Self {
|
||||
const ESPLUGIN_ERROR_UNKNOWN: (i32, &str) = (
|
||||
esplugin::ESP_ERROR_UNKNOWN,
|
||||
"Could not retrieve esplugin error message",
|
||||
);
|
||||
|
||||
from_error(
|
||||
value,
|
||||
SystemErrorCategory::Esplugin,
|
||||
ESPLUGIN_ERROR_UNKNOWN,
|
||||
crate::esplugin::map_error,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn from_error<U: Error, V: Error + 'static, F: Fn(&V) -> c_int>(
|
||||
error: U,
|
||||
category: SystemErrorCategory,
|
||||
default: (i32, &'static str),
|
||||
to_code: F,
|
||||
) -> SystemError {
|
||||
let (code, message) = error
|
||||
.source()
|
||||
.and_then(|s| s.downcast_ref::<V>())
|
||||
.map_or_else(
|
||||
|| (default.0, default.1.to_owned()),
|
||||
|e| (to_code(e), e.to_string()),
|
||||
);
|
||||
|
||||
SystemError {
|
||||
code,
|
||||
category,
|
||||
message,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub struct UnsupportedEnumValueError;
|
||||
|
||||
Reference in New Issue
Block a user